Правильный запрос sql / hql (агрегат в предложении where) - PullRequest
4 голосов
/ 22 января 2010

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

SELECT name, dateTime, data
FROM Record
WHERE dateTime = MAX(dateTime)

Обновление: ОК. Запрос описывает намерения не совсем хорошо. Мой плохой.

Я хочу выбрать последнюю запись для каждого человека.

Ответы [ 4 ]

5 голосов
/ 22 января 2010

Попробуйте:

SELECT name, dateTime, data
FROM Record 
WHERE dateTime = SELECT MAX(dateTime) FROM Record

Вы также можете написать это, используя внутреннее соединение:

SELECT R.name, R.dateTime, R.data
FROM Record R
  INNER JOIN (SELECT MAX(dateTime) FROM Record) RMax ON R.dateTime = RMax.dateTime

То же самое, но написано с другой точки зрения

SELECT R.name, R.dateTime, R.data
FROM Record R,
     (SELECT MAX(dateTime) FROM Record) RMax
WHERE R.dateTime = RMax.dateTime
2 голосов
/ 22 января 2010

Мне нравится ответ Мики и Quassnoi (и голос Мики проголосовал), но, если ваши потребности похожи на мои, вы должны иметь в виду некоторые ограничения. Первое и самое главное, это работает, только если вы ищете последнюю запись в целом или последнюю запись для одного имени. Если вам нужна последняя запись для каждого человека в наборе (по одной записи на человека, но самая последняя запись для каждого), то вышеприведенные решения не годятся. Во-вторых, и что не менее важно, если вы будете работать с большими наборами данных, это может оказаться немного медленным в долгосрочной перспективе. Итак, что такое обходной путь?

Что я делаю, так это добавляю битовое поле в таблицу, помеченную как «новейшая». Затем, когда я сохраняю запись (что делается в хранимой процедуре в SQL Server), я следую этому шаблону:

Update Table Set Newest=0 Where Name=@Name
Insert into Table (Name, dateTimeVal, Data, Newest) Values (@Name, GetDate(), @Data, 1);

Также есть указатель на Name и Newest для быстрого выбора.

Тогда выбор просто:

Select dateTimeVal, Data From Table Where (Name=@Name) and (Newest=1);

Выбор для группы будет выглядеть примерно так:

Select Name, dateTimeVal, Data from Table Where (Newest=1);  -- Gets multiple records

Если записи не могут быть введены в порядке дат, то ваша логика немного отличается:

Update Table Set Newest=0 Where Name=@Name
Insert into Table (Name, dateTimeVal, Data, Newest) Values (@Name, GetDate(), @Data, 0); -- NOTE ZERO
Update Table Set Newest=1 Where dateTimeVal=(Select Max(dateTimeVal) From Table Where Name=@Name);

Остальное остается прежним.

2 голосов
/ 22 января 2010

В MySQL и PostgreSQL:

SELECT  name, dateTime, data
FROM    Record
ORDER BY
        dateTime DESC
LIMIT 1

В SQL Server:

SELECT  TOP 1 name, dateTime, data
FROM    Record
ORDER BY
        dateTime DESC

В Oracle

SELECT  *
FROM    (
        SELECT  name, dateTime, data
        FROM    Record
        ORDER BY
                dateTime DESC
        )
WHERE   rownum = 1

Обновление:

Чтобы выбрать одного человека для каждой записи, в SQL Server используйте это:

WITH    q AS
        (
        SELECT  *, ROW_NUMBER() OVER (PARTITION BY person ORDER BY dateTime DESC)
        FROM    Record
        )
SELECT  *
FROM    q
WHERE   rn = 1

или это:

SELECT  ro.*
FROM    (
        SELECT  DISTINCT person
        FROM    Record
        ) d
CROSS APPLY
        (
        SELECT  TOP 1 *
        FROM    Record r
        WHERE   r.person = d.person
        ORDER BY
                dateTime DESC
        ) ro

Смотрите эту статью в моем блоге:

для преимуществ и недостатков обоих решений.

0 голосов
/ 18 октября 2010

Я попробовал совет Милки, но все три способа построения подзапроса привели к ошибкам синтаксического анализатора HQL.

Что работает, хотя это небольшое изменение первого метода (добавлены дополнительные скобки).

SELECT name, dateTime, data
FROM Record 
WHERE dateTime = (SELECT MAX(dateTime) FROM Record)

PS: Это просто для указания на очевидное для новичков в HQL и тому подобное. Думаю, это поможет.

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