Безопасно ли включать дополнительные столбцы в список SELECT запроса SQLite GROUP BY? - PullRequest
2 голосов
/ 18 ноября 2009

У меня есть простая таблица SQLite под названием «message»:

sequence INTEGER PRIMARY KEY
type TEXT
content TEXT

Я хочу получить содержимое последнего сообщения каждого типа (в зависимости от его последовательности). К моему удивлению, работает следующий простой запрос:

SELECT MAX(sequence), type, content
FROM message
GROUP BY type

Удивительно, потому что я знаю, что MSSQL или Postgres отказались бы включать в список SELECT столбец, который не является частью предложения GROUP BY или агрегатной функции, и мне нужно было бы выполнить объединение, например так:

SELECT m.sequence, m.type, m.content
FROM
(
    SELECT MAX(sequence) as sequence, type
    FROM message
    GROUP BY type
) g
JOIN message m
ON g.sequence = m.message_sequence

У меня вопрос: безопасно ли использовать первую, гораздо более простую форму запроса в SQLite? Интуитивно понятно, что он выбирает значение «content», соответствующее значению «MAX (sequence)», но в документации, похоже, об этом вообще не говорится. Конечно, если последовательность не уникальна, результат будет неопределенным. Но если последовательность уникальна, как в моем случае, это гарантировано или это просто удачная деталь реализации, которая может быть изменена?

Ответы [ 3 ]

6 голосов
/ 18 ноября 2009

Вы можете использовать эти запросы «безопасно», то есть без получения неоднозначных результатов, если дополнительные столбцы функционально зависят от столбцов, которые вы группируете по:

SELECT c.parent_id, COUNT(*), p.any_column
FROM child_table c 
JOIN parent_table p USING (parent_id)
GROUP BY c.parent_id;

Приведенный выше пример будет работать в SQLite и давать однозначный результат, поскольку нет способа, чтобы p.any_column мог иметь несколько значений на группу. Однако этот запрос строго нарушает стандарт SQL, и большинство брендов СУБД вызовут ошибку.

Слишком легко написать запрос, который дает неоднозначные результаты. Когда вы называете столбец с несколькими значениями на группу, вы не можете контролировать, какое значение возвращается в вашем наборе результатов.

На практике MySQL возвращает значение из строки first относительно физического хранилища, а SQLite возвращает значение из строки last . Но это полностью зависит от реализации и не надежно. Если следующая версия любого программного обеспечения изменит свои внутренние компоненты, вы можете получить другие результаты запроса после обновления. Поэтому лучше не полагаться на это поведение.


Что касается вашего примера, где content должен «интуитивно» иметь значение из строки, где sequence - MAX. Но действительно ли это интуитивно понятно? Рассмотрим эти другие случаи:

SELECT MAX(sequence), MIN(sequence), type, content
FROM message
GROUP BY type

Так, какая строка теперь предоставляет значение для content? Строка, где sequence - МАКС., Или строка, где sequence - МИН.?

Что делать, если вы используете неуникальный столбец (например, date), и есть несколько строк с одинаковым значением MAX для date, но разными значениями для content?

SELECT MAX(date), type, content
FROM message
GROUP BY type

А как насчет других агрегатных функций, таких как AVG() или SUM()? Возможно, что значение агрегата не соответствует отдельной строке таблицы. Итак, какая строка должна содержать значение для content?

SELECT AVG(sequence), type, content
FROM message
GROUP BY type
1 голос
/ 18 ноября 2009

Я не знаю ни одной базы данных, которая "интуитивно" решала бы проблему такого рода, где вы хотите получить связанные значения строк для группы на основе результата агрегата для определенного столбца. Что касается SQLite, я думаю, вам лучше придерживаться второго запроса.

Поскольку вы упомянули PostgreSQL, стоит отметить, что он поддерживает некоторый нестандартный синтаксис, который выполняет это, в виде DISTINCT ON:

select distinct on (type) sequence, type, content
from message
order by sequence desc

(В этом могут быть некоторые ошибки, так как передо мной нет приглашения psql, но в этом суть.)

См. http://www.postgresql.org/docs/8.4/interactive/queries-select-lists.html

0 голосов
/ 18 ноября 2009

Бьюсь об заклад, он просто использует случайное значение для поля последовательности. Например, документы MySQL прямо говорят об этом.

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