Возможно ли иметь SQL-запрос, который использует функции AGG таким образом? - PullRequest
3 голосов
/ 24 октября 2011

Предполагая, что у меня есть следующие агрегатные функции:

  • AGG1
  • AGG2
  • AGG3
  • AGG4

Можно ли написать действительный SQL (без учета базы данных) следующим образом:

SELECT [COL1, COL2 ....], AGG1(param1), AGG2(param2) FROM [SOME TABLES]
WHERE [SOME CRITERIA]
HAVING AGG3(param2) >-1 and AGG4(param4) < 123
GROUP BY COL1, COL2, ... COLN
ORDER BY COL1, COLN ASC
LIMIT 10

Где COL1 ... COLN - столбцы в запрашиваемых таблицах, а param1 ... paramX - параметры, передаваемые в функции AGG.

Примечание: AGG1 и AGG2 возвращаются в результатах в виде столбцов (но не отображаются в HAVING CLAUSE, а AGG3 и AGG4 появляются в HAVING CLAUSE, но не возвращаются в наборе результатов.

В идеале мне нужен независимый от БД ответ на решение, но если мне нужно привязаться к БД, я использую PostgreSQL (v9.x).

Редактировать

Просто уточнение: я не против использования GROUP BY в запросе. Мой SQL не очень хорош, поэтому приведенный выше пример SQL может немного вводить в заблуждение. Я отредактировал псевдо sql заявление выше, чтобы, надеюсь, прояснить свои намерения.

Главное, что я хотел выяснить, могло ли запрос select, использующий функции AGG:

  • Содержит значения функций agg в возвращаемом столбце без указания их в предложении HAVING.
  • Содержат функции agg, указанные в предложении HAVING, но не возвращаются в наборе результатов.

Из ответов, которые я получил до сих пор, казалось бы, ответ на оба вопроса - ДА. Единственное, что мне нужно сделать, чтобы исправить мой SQL, - это добавить предложение GROUP BY, чтобы убедиться, что возвращаемые строки уникальны.

Ответы [ 3 ]

1 голос
/ 24 октября 2011

Основная версия PostgreSQL включает первую цифру после точки, поэтому "PostgreSQL (v9.x)" недостаточно конкретен.Как сказал @kekekela, не существует (дешевого) полностью независимого от db способа.Даже между PostgreSQL 9.0 и 9.1 есть важное синтаксическое различие.

Если бы у вас были только сгруппированные значения AGG1(param1), AGG2(param2), вы бы обошлись без предоставления явного предложения GROUP BY.Поскольку вы смешиваете сгруппированные и не сгруппированные столбцы, вы должны предоставить предложение GROUP BY со всеми не сгруппированными столбцами, которые отображаются в SELECT.Это верно для любой версии PostgreSQL.Прочтите о GROUP BY и поместите его в руководство .

Начиная с версии 9.1 , однако, как только вы перечислите первичный ключ в GROUP BY, вы можете пропуститьдополнительные столбцы для этой таблицы и по-прежнему использовать их в списке SELECT.Замечания к выпуску для версии 9.1 говорят нам:

Разрешить столбцы не-GROUP BY в списке целей запроса, когда первичный ключ указан в предложении GROUP BY (Питер Эйзентраут)

Относительно параметров

Намереваетесь ли вы передать постоянное значение в агрегатную функцию?В чем смысл? документы говорят нам

Агрегатная функция вычисляет один результат из нескольких входных строк.

Или вы хотите, чтобы эти параметры были именами столбцов?Этот вид динамического SQL работает до тех пор, пока оператор генерируется до фиксации в базе данных.Не работает для подготовленных операторов или простых функций sql или plpgsql.Для этой цели вы должны использовать EXECUTE в функции plpgsql.

В качестве защиты от SQLi используйте синтаксис USING $1, $2 для значений и quote_ident() для вашего столбца или таблицы имена .

1 голос
/ 24 октября 2011

Единственный способ агрегирования по столбцам без использования GROUP BY - это использовать функции управления окнами. Вы не указали детали своей проблемы, но вам может понадобиться следующее:

SELECT *
FROM (
    SELECT [COL1, COL2 ....], 
           AGG1(param1) over (partition by some_grouping_column) as agg1, 
           AGG2(param2) over (partition by some_grouping_column) as agg2,
           row_number() over () as rn
    FROM [SOME TABLES]
    WHERE [SOME CRITERIA]
    ORDER BY COL1
)  t
WHERE AGG3 >-1 
  AND AGG4 < 123
  AND rn <= 10
ORDER BY col1

Это стандартный ANSI SQL, который работает с большинством баз данных, включая PostgreSQL (начиная с 8.4).

Обратите внимание, что вам не нужно использовать один и тот же столбец группировки для обоих агрегатов в разделе по разделам.

Если вы хотите придерживаться ANSI SQL, вам следует использовать функцию row_number(), чтобы ограничить результат. Если вы запускаете это только на PostgreSQL (или другой СУБД, которая каким-то образом поддерживает LIMIT), переместите причину LIMIT в производную таблицу (внутренний запрос)

0 голосов
/ 24 октября 2011

Это должно работать с точки зрения высокого уровня, за исключением того, что вам понадобятся COL1, COL2 и т. Д. В выражении GROUP BY, иначе они не будут действительны в списке SELECT. Наличие AGG1 и т. Д. В списке SELECT, а не в HAVING - не проблема.

Что касается db-агностики, то вам придется настраивать синтаксис независимо от того, что вы делаете (например, LIMIT будет отличаться в PostgreSQL, SQL SERVER и Oracle, которые я знаю из головы) , но вы могли бы построить логику для правильного построения операторов для каждого при условии, что ваше высокоуровневое представление является надежным.

...