Включить неагрегированный столбец в группу по выражению (с небольшой складкой) - PullRequest
0 голосов
/ 13 января 2012

У меня есть таблица, которая выглядит примерно так:

timestamp                value           person
===============================================
2010-01-12 00:00:00       33              emp1
2010-01-12 11:00:00       22              emp1
2010-01-12 09:00:00       16              emp2
2010-01-12 08:00:00       16              emp2
2010-01-12 12:12:00       45              emp3
2010-01-12 13:44:00       64              emp4
2010-01-12 06:00:00       33              emp1
2010-01-12 15:00:00       12              emp5

Я хотел найти максимальное значение, связанное с каждым человеком. Очевидный запрос был:

select person,max(value) from table group by person

Теперь я хотел включить метку времени, связанную с каждым максимумом (значением). Я не мог использовать столбец отметки времени в приведенном выше запросе, потому что, как все знают, он не будет отображаться в предложении group by. Поэтому я написал это вместо:

select x.timestamp,x.value,x.person from table as x,
(select person,max(value) as maxvalue from table group by person order by maxvalue 
 desc) as y
where x.person = y.person
and x.value = y.maxvalue

Это работает - до некоторой степени. Теперь я вижу:

timestamp                value           person
===============================================
2010-01-12 13:44:00       64              emp4
2010-01-12 12:12:00       45              emp3
2010-01-12 06:00:00       33              emp1
2010-01-12 00:00:00       33              emp1
2010-01-12 08:00:00       16              emp2
2010-01-12 09:00:00       16              emp2
2010-01-12 15:00:00       12              emp5

Проблема в том, что теперь я получаю все записи для emp1 и emp2, которые заканчиваются одинаковым max (значением).

Предположим, среди emp1 и emp2 я хочу видеть запись только с последней отметкой времени. Я хочу это:

timestamp                value           person
===============================================
2010-01-12 13:44:00       64              emp4
2010-01-12 12:12:00       45              emp3
2010-01-12 06:00:00       33              emp1
2010-01-12 09:00:00       16              emp2
2010-01-12 15:00:00       12              emp5

Какой запрос мне нужно написать? Можно ли расширить вложенный запрос, который я написал, чтобы достичь того, чего я хочу, или нужно переписать все с нуля?

Если это важно, потому что я использую Sqlite, отметки времени фактически сохраняются как юлианские дни. Я использую функцию datetime () для преобразования их обратно в строковое представление в каждом запросе.

1 Ответ

1 голос
/ 14 января 2012

Вы были почти там:

SELECT max(x.timestamp) AS timestamp, x.value, x.person
     , y.max_value, y.ct_value, y.avg_value
FROM   table AS x
JOIN  (
    SELECT person
         , max(value) as max_value
         , count(value) as ct_value
         , avg(value) as avg_value
    FROM   table
    GROUP  BY person
    ) AS y ON (x.person, x.value) = (y.person, y.max_value)
GROUP BY x.person, x.value, y.max_value, y.ct_value, y.avg_value
-- ORDER  BY x.person, x.value

Вы не можете вычислить max(x.timestamp) в том же вложенном запросе, потому что вам нужен не абсолютный максимум на человека, а тот, который сопровождает максимальное значение. Таким образом, вам нужно объединиться в другой раз на следующем уровне запроса.

Вычислите max(x.timestamp) перед тем, как преобразовать его в строковое представление - хотя ваш формат также будет правильно сортироваться. Но это должно работать лучше.

Обратите внимание, как я трансформировал ваше перекрестное соединение с тем, где условия в [внутреннее] соединение с (упрощенным) условием соединения. Делает то же самое, просто как канонический способ стандарта SQL и более читабелен.

Все это может быть выполнено на одном уровне запросов с оконными функциями (max() и first_value()), которые реализованы во всех больших СУБД (кроме MYSQL), но не в SQLite.


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

Включены дополнительные агрегаты после запроса в комментарии.

...