У меня есть отношение таблицы, которое выглядит следующим образом:
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.
Любые идеи?
Это действительно должно дать вам ошибку вместо того, чтобы возвращать данные 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
)
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
И обычно это лучший способ иметь две таблицы: одна содержит текущее состояние, другая содержит исторические данные.
Вам нужно использовать подзапрос:
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)
и т.д.
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)
, чтобы он работал быстро.
Смотрите эту статью в своем блоге для получения более подробной информации: