Почему FIRST_VALUE и LAST_VALUE не являются функцией агрегирования в SQL? - PullRequest
0 голосов
/ 18 апреля 2020

Есть ли какая-то особая причина, по которой SQL реализует только FIRST_VALUE и LAST_VALUE как оконную функцию вместо функции агрегирования? Я нахожу довольно часто встречаться с такими проблемами, как «найти предмет с самой высокой ценой в каждой категории». В то время как другие языки (такие как python) предоставляют функции MIN / MAX с ключевыми словами, так что возможен

MAX(item_name, key=lambda x: revenue[x])

, в SQL единственным способом решения этой проблемы является:

WITH temp as(
SELECT *, FIRST_VALUE(item_name) OVER(PARTITION BY category ORDER BY revenue) as fv
FROM catalog)
SELECT category, MAX(fv) -- MIN(fv) also OK
FROM temp
GROUP BY category;

Есть ли особая причина, по которой не существует "версии агрегирования" FIRST_VALUE, такой, что

SELECT category, FIRST_VALUE(item_name, revenue)
FROM catalog
GROUP BY
category

, или это просто так?

1 Ответ

2 голосов
/ 18 апреля 2020

Насколько я понимаю, так оно и есть. Я подозреваю, что единственный реальный ответ был бы «потому что это не в спецификации SQL», и единственные люди, которые могли бы действительно ответить относительно почему это не в спецификации c, это люди, которые пишут это , Вопросы вида «о чем (название соответствующего внешнего органа) думают, когда они предписывают, что (название продукта) должно работать следующим образом» на самом деле, как правило, здесь не так: c, потому что очень немногие люди могут надежно и на самом деле отвечаю .. Мне даже не нравится мой собственный ответ здесь, так как он выглядит как расширенный комментарий к вопросу, на который невозможно дать реалистичный ответ

Агрегатные функции работают с наборами данных, и хотя некоторые из них могут требуется некоторая подразумеваемая операция упорядочения, такая как медиана, функции всегда относятся к столбцу, с которым они работают, а не «дайте мне значение этого столбца на основе упорядочения этого столбца».

Существует множество оконных / аналитических c функций, которые не имеют версии агрегации следствия, а оконные функции имеют другое конечное назначение, нежели агрегация. Можно предположить, что некоторые из них выполняют агрегацию, а затем присоединяют результат агрегации обратно к основным данным, чтобы связать результат агрегирования с конкретной строкой, но я бы не предположил, что эти два средства (агг против окна) вообще связаны между собой.

Насколько я понимаю python (не python dev), он не выполняет агрегацию, он ищет список строк item_name и просматривает каждую из них в словаре, который возвращает доход для этот предмет, и возвращая item_name, который имеет наибольший доход. Там не было никакой группировки, она больше похожа на SELECT TOP 1 item_name ORDER BY revenue и действительно хороша только для возврата одного элемента, а не для загрузки элементов, которые являются максимальными в пределах их группы, если только они не используются в пределах oop, которые каждый раз обрабатывает другой список имен элементов


Я знаю, что ваш вопрос был не совсем об этом конкретном SQL запросе, но может быть полезно, если я упомяну несколько вещей о нем , Я не совсем уверен, что:

WITH temp as(
  SELECT *, FIRST_VALUE(item_name) OVER(PARTITION BY category ORDER BY revenue) as fv
  FROM catalog
)
SELECT category, MAX(fv) -- MIN(fv) also OK
FROM temp
GROUP BY category;

Дает вам что-то вроде:

SELECT DISTINCT category, FIRST_VALUE(item_name) OVER(PARTITION BY category ORDER BY revenue) as fv
FROM catalog

Analytic / window будет выдавать одинаковое значение для каждой категории (раздела), поэтому Кажется, что на самом деле все, что делает дополнительная группа, - это уменьшение повторяющихся значений - на которые можно было бы проще ответить, просто получив нужные значения и использовав различные, чтобы определить количество sh дубликатов (один из немногих случаев, когда я бы выступал за такое )

В более общем смысле «Я хочу, чтобы вся самая большая строка X определялась по максимальному / минимальному Y», мы обычно используем для этого номер строки:

WITH temp as(
  SELECT *, ROW_NUMBER(item_name) OVER(PARTITION BY category ORDER BY revenue) as rn
FROM catalog)
SELECT *
FROM temp
WHERE rn = 1;

Хотя я нахожу его более компактный / читаемый, чтобы обойтись без CTE и просто использовать подзапрос, но YMMV

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...