Apakah SQL Spec memerlukan GROUP BY dalam EXISTS ()


11

Microsoft saat ini mengizinkan sintaks ini.

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT *
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  HAVING count(*) > 1
);

Perhatikan bahwa tidak ada GROUP BYdalam EXISTSklausa, apakah itu ANSI SQL yang valid. Atau itu hanya mengekspos detail implementasi.

Sebagai referensi, sintaksis yang sama ini tidak diizinkan di PostgreSQL.

GALAT: kolom "tx" harus muncul dalam klausa GROUP BY atau digunakan dalam fungsi agregat

Tapi sintaks ini diizinkan ..

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT 1  -- This changed from the first query
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  HAVING count(*) > 1
);

Dan sintaks ini diizinkan.

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT *
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  GROUP BY t.x  -- This changed from the first query
  HAVING count(*) > 1
);

Pertanyaan muncul dari percakapan dengan @ErikE dalam obrolan

Jawaban:


11

Saya menemukannya di spec SQL 2011 ...

Jika <select list>"*" hanya terkandung dalam suatu <table subquery>yang langsung terkandung dalam <exists predicate>, maka <select list>itu setara dengan <value expression>yang adalah sewenang-wenang <literal>.

Ini menegaskan bahwa dengan *tidak setara dengan literal sewenang-wenang dalam konteks ini bahwa itu sebenarnya adalah PostgreSQL yang melanggar spesifikasi.

Perlu diingat bahwa ini adalah masalah yang berbeda

SELECT *
FROM ( VALUES (1),(2),(3) ) AS t(x)
HAVING count(*) > 1

Yang ditolak kedua basis data.

PostgreSQL,

GALAT: kolom "tx" harus muncul dalam klausa GROUP BY atau digunakan dalam fungsi agregat

SQL Server,

Kolom 'tx' tidak valid dalam daftar pilih karena tidak terkandung dalam fungsi agregat atau klausa GROUP BY.

Mengapa bug ini tetap ada di PostgreSQL

Terima kasih kepada RhodiumToad di irc.freenode.net/#PostgreSQL untuk masalah bantuannya dalam memotret ini. Dia juga menunjukkan kesulitan dalam menyelesaikan situasi ini

20:33 <RhodiumToad> satu-satunya masalah adalah bahwa di pg Anda dapat melakukannya ada (pilih func () dari ... di mana func () adalah SRF yang mungkin mengembalikan 0 baris

SRF adalah fungsi pengembalian set.

Dalam PostgreSQL, kita dapat melakukan misalnya menggunakan SRF untuk menghasilkan seri dari 1-10 ( generate_seriesada di inti)

SELECT * FROM generate_series(1,10); 

Dan, kita juga bisa meletakkannya di sini.

SELECT generate_series(1,10);

Dua dari mereka bersama-sama memberi kami cross-join (produk kartesian)

SELECT generate_series(1,10), generate_series(1,2);

Tapi, jika salah satu dari mereka mengembalikan 0-baris Anda tidak mendapatkan apa-apa .. Secara efektif sama seperti ini

SELECT * FROM ( VALUES (1) ) AS t(x)
CROSS JOIN ( SELECT 1 LIMIT 0 ) AS g;

Dan, itulah masalah dengan mengoptimalkan ini sepenuhnya. Anda dapat memiliki SRF dalam daftar pilih di dalam pernyataan ADA yang mengembalikan 0-baris, dan memaksa ADA untuk mengevaluasi ke false.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.