Чи потрібна специфікація SQL для GROUP BY EXISTS ()


11

На даний момент Microsoft дозволяє цей синтаксис.

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
);

Зауважте, що GROUP BYв EXISTSпункті немає, це дійсний ANSI SQL. Або це лише викриття деталей реалізації.

Для довідки, цей самий синтаксис не дозволений у PostgreSQL.

ПОМИЛКА: стовпець "tx" повинен з'являтися в пункті GROUP BY або використовуватись у сукупній функції

Але цей синтаксис дозволений ..

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
);

І цей синтаксис дозволений.

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
);

Питання виникає з розмови з @ErikE у чаті

Відповіді:


11

Я знайшов це в специфікації SQL 2011 ...

Якщо <select list>"*" просто міститься в a, <table subquery>яке негайно міститься в an <exists predicate>, то значення <select list>еквівалентне <value expression>довільному <literal>.

Це підтверджує, що, *не будучи еквівалентним довільному літералу в цьому контексті, це насправді PostgreSQL порушує специфікацію.

Майте на увазі, що це окрема проблема

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

Які обидві бази даних відкидають.

PostgreSQL,

ПОМИЛКА: стовпець "tx" повинен з'являтися в пункті GROUP BY або використовуватись у сукупній функції

SQL Server,

Стовпець 'tx' недійсний у списку вибору, оскільки він не міститься ні в сукупній функції, ні в пункті GROUP BY.

Чому ця помилка зберігається в PostgreSQL

Дякуємо RhodiumToad на irc.freenode.net/#PostgreSQL за допомогу в роботі з цим. Він також вказує на складність у вирішенні цієї ситуації

20:33 <RhodiumToad> одна проблема полягає в тому, що в pg ви можете зробити (виберіть func () з ... де func () - це SRF, який може повернути 0 рядків

SRF - це задана функція повернення.

У PostgreSQL ми можемо зробити, наприклад, використання SRF для генерації серії від 1-10 ( generate_seriesє в ядрі)

SELECT * FROM generate_series(1,10); 

І ми також можемо це зробити прямо тут.

SELECT generate_series(1,10);

Дві з них разом дають нам перехресне з'єднання (декартовий продукт)

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

Але якщо будь-який з цих повертає 0-рядки, ви нічого не отримаєте. Фактично такий же, як і цей

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

І ось в чому проблема цілком оптимізована. Ви можете мати SRF у списку вибору всередині оператора EXIST, який повертає 0 рядків, і змушує EXISTS оцінювати значення false.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.