Функция агрегирования, возвращающая данные первой строки для столбца, не входящего в группу,

0

У меня есть отношение таблицы, которое выглядит следующим образом:

barn
------
PK barn_id
<other columns>

stable
---------
PK stable_id
FK barn_id
stable_number
stable_contents
timestamp

Поэтому всякий раз, когда содержимое стабильного изменения я просто помещаю в новую строку с соответствующими barn_id и stable_number с новыми stable_contents и текущей меткой времени.

Таблицы разработаны таким образом, чтобы я мог смотреть на определенную стабильность и видеть всю ее историю.

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

SELECT barn_id, stable_number, max(timestamp), stable_contents
FROM stable
GROUP BY barn_id, stable_number

В моих тестовых данных у меня есть несколько строк, подобных этому для сарая 1, стабильный 7

1 | 7 | 2009-12-09 10:00:00 | empty
1 | 7 | 2009-12-10 10:30:00 | show horse

Если я запустил запрос SELECT выше, я получаю следующую строку, возвращенную для barn 1, stable 7:

1 | 7 | 2009-12-10 10:30:00 | empty

он получает правильную максимальную временную метку, только неправильные stable_contents.

Любые идеи?

Теги:

4 ответа

0
Лучший ответ

Это действительно должно дать вам ошибку вместо того, чтобы возвращать данные undefined, потому что вы пытаетесь получить неагрегированные данные, которых нет в вашей GROUP BY (stable_contents). Я бы использовал следующий запрос, который находит все строки для стабильной таблицы, где нет строки после нее для той же стабильной:

SELECT
     T1.barn_id,
     T1.stable_number,
     T1.timestamp,
     T1.stable_contents
FROM
     Stable AS T1
LEFT OUTER JOIN Stable AS T2 ON
     T2.barn_id = T1.barn_id AND
     T2.stable_number = T1.stable_number AND
     T2.timestamp > T1.timestamp
WHERE
     T2.barn_id IS NULL     -- The only way for this to be NULL is if no match was found

В качестве альтернативы:

SELECT
     T1.barn_id,
     T1.stable_number,
     T1.timestamp,
     T1.stable_contents
FROM
     Stable AS T1
WHERE
     NOT EXISTS
     (
          SELECT
               *
          FROM
               Stable AS T2
          WHERE
               T2.barn_id = T1.barn_id AND
               T2.stable_number = T1.stable_number AND
               T2.timestamp > T1.timestamp
     )
  • 0
    Я выбрал этот вариант, потому что альтернативная версия прекрасно портирована на hql. Спасибо за все представленные материалы.
0
SELECT s.*
FROM (
    SELECT barn_id, stable_number, max(timestamp) as timestamp
    FROM stable
    GROUP BY barn_id, stable_number) d
INNER JOIN stable s ON s.barn_id = d.barn_id
                       AND s.stable_number = d.stable_number
                       AND s.timestamp = d.timestamp

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

0

Вам нужно использовать подзапрос:

SELECT barn_id, stable_number, timestamp, stable_contents
FROM stable
WHERE (barn_id, stable_number, timestamp) IN 
(SELECT barn_id, stable_number, max(timestamp) as timestamp
FROM stable
GROUP BY barn_id, stable_number)

Если вы не сообщите об этом, база данных не сможет узнать, что вы хотите получить стабильное содержимое из строки с наивысшей отметкой времени. У вас может быть запрос с несколькими предложениями агрегации max(timestamp), min(timestamp) и т.д.

0
SELECT  s.*
FROM    barn b
JOIN    stable s
ON      stable_id = 
        (
        SELECT  stable_id
        FROM    stable si
        WHERE   si.barn_id = b.id
        ORDER BY
                barn_id DESC, timestamp DESC, stable_id DESC
        )

Убедитесь, что у вас есть составной индекс на stable (barn_id, timestamp, stable_id), чтобы он работал быстро.

Смотрите эту статью в своем блоге для получения более подробной информации:

Ещё вопросы

Сообщество Overcoder
Наверх
Меню