#sql #sqlite #join #subquery #inner-join
#sql #sqlite #Присоединиться #подзапрос #внутреннее соединение
Вопрос:
У меня есть SQL-запрос в соответствии с:
SELECT * FROM a
INNER JOIN
(
SELECT date, MAX(z) FROM a
WHERE a.x = "foo" AND a.y IN (1, 2, 3)
GROUP BY z
) b
ON a.date = b.date
WHERE a.x = "foo" AND a.y IN (1, 2, 3)
Мой вопрос в том, пахнет ли кодом это повторяющееся условие WHERE? Возможно, ответ зависит от конкретного контекста, но я надеюсь на ответ «в целом» или некоторые указания на то, как я мог бы улучшить его.
Комментарии:
1. Это даже не компилируется: вы не можете группировать по выражению, которое вы агрегируете. Я не знаю, что вы пытаетесь сделать, по
group by date
крайней мере, скомпилировать. Пожалуйста, исправьте свой запрос, чтобы он был синтаксически корректным2. Можете ли вы предоставить некоторые примеры данных и ожидаемый результат? Вероятно, есть гораздо более простое решение, чем ваш запрос.
3. @Bohemian, ты можешь объяснить? Он компилируется здесь: db-fiddle.com/f/xevfg5qvjeuVDy57uMV69E/1 . Я скопировал / вставил непосредственно в свой вопрос.
4. @TheImpaler, это не для конкретного примера. Я спрашиваю о том, повторяются ли условия WHERE «НОРМАЛЬНО» или нет, или всегда есть лучший способ. Если вы считаете, что это зависит от конкретного примера, пожалуйста, так и скажите.
5. @jarthur повторил условия WHERE, если они решают проблему, и лучшей альтернативы нет. В вашем случае неясно, что вы хотите сделать. Если вы уточните свое требование, возможно, мы сможем предложить лучшее решение.
Ответ №1:
Этот подзапрос:
SELECT date, MAX(z) FROM a
WHERE a.x = "foo" AND a.y IN (1, 2, 3)
GROUP BY z
разрешено в SQLite, но это было бы недопустимо в большинстве других баз данных, потому GROUP BY z
что, хотя вы также выполняете агрегирование z
и выбираете неагрегированный столбец date
.
В любом случае, что делает этот запрос, это фильтрует таблицу в соответствии с условиями WHERE
предложения, а затем возвращает 1 строку для каждого отдельного z
(поскольку MAX(z)
фактически равно z
в его собственной группе) с произвольным значением for date
.
Затем вы соединяете таблицу с помощью подзапроса this в произвольные даты, которые возвращает подзапрос. Все это очень неясно в отношении того, что вы имеете в виду в качестве ожидаемого результата.
Но, если вас беспокоят повторяющиеся условия, то я должен сказать, что всегда лучше, если вы можете их избежать.
В вашем случае есть решение a CTE
, потому что в вашем основном запросе и вашем подзапросе вы выполняете одну и ту же фильтрацию, поэтому вас интересуют только строки, для которых выполняются эти условия:
a.x = "foo" AND a.y IN (1, 2, 3)
Таким образом, вы можете получить такие же результаты, как это:
WITH cte AS (
SELECT * FROM a
WHERE a.x = "foo" AND a.y IN (1, 2, 3)
)
SELECT *
FROM cte c
INNER JOIN (
SELECT date, MAX(z) FROM cte
GROUP BY z
) b ON b.date = c.date
Смотрите демонстрацию.
Комментарии:
1. «Но, если вас беспокоят повторяющиеся условия, тогда я должен сказать, что всегда лучше, если вы можете их избежать». Это было действительно то, что я искал. Я должен был больше подчеркнуть, что пример запроса в OP на самом деле не имеет отношения к делу (в моем фактическом запросе нет
GROUP BY
проблемы с агрегацией — это был недосмотр с моей стороны). Также благодарим вас за публикацию альтернативного решения, это очень полезно.
Ответ №2:
Используйте оконные функции. Если вам нужна максимальная дата на z:
SELECT a.*,
MAX(z) OVER (PARTITION BY date)
FROM a
WHERE a.x = "foo" AND a.y IN (1, 2, 3);
Ответ №3:
Предполагая, что вам нужно максимальное z
значение для the date
, тогда вам нужны оба where
предложения, потому что без его where
предложения подзапрос вернул бы max z
для любой строки для the date
, а не max z
для строк, которые вы запрашиваете.
В вашем запросе есть небольшая ошибка: подзапрос должен использовать GROUP BY date
, а не GROUP BY z
:
SELECT * FROM a
INNER JOIN
(
SELECT date, MAX(z) FROM a
WHERE a.x = "foo" AND a.y IN (1, 2, 3)
GROUP BY date
) b
ON a.date = b.date
WHERE a.x = "foo" AND a.y IN (1, 2, 3)