Требует ли спецификация 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>который непосредственно содержится в a <exists predicate>, то <select list>эквивалентно a, <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.

Эван Кэрролл
источник