#sql #group-by
#sql #группировать по
Вопрос:
Я работаю с таблицей «Маршрут», в которой подробно описывается упорядоченный набор «Этапов» для конкретного ProductID:
| ID | ProductID | StageID | Order |
|---- ----------- --------- -------|
| 0 | 1 | 4 | 1 |
| 1 | 1 | 2 | 2 |
| 2 | 1 | 3 | 3 |
| 3 | 1 | 7 | 4 |
| 4 | 1 | 5 | 5 |
|---- ----------- --------- -------|
И таблицу записей, в которой подробно указаны результаты прохождения / сбоя с отметкой времени для серийного номера продукта на определенном этапе:
| ID | RecordDate | Serial Number | StageID | Result |
|---- --------------------- --------------- --------- --------|
| 0 | 2019-03-16 00:00:00 | G001 | 4 | 1 |
| 1 | 2019-03-16 00:01:00 | G001 | 2 | 1 |
| 2 | 2019-03-16 00:02:00 | G001 | 2 | 0 |
|---- --------------------- --------------- --------- --------|
Из приведенных выше гипотетических данных вы можете видеть, что серийный номер G001 прошел этап 4 и ПРОШЕЛ, затем этап 2 и ПРОШЕЛ, но затем он снова прошел этап 2 и ПОТЕРПЕЛ НЕУДАЧУ.
Теперь я хочу выбрать результаты из этой таблицы записей для определенного SerialNumber, где StageID существует в маршруте для этого продукта. Это просто — вот мой запрос:
SELECT StageID, Result, RecordDate
FROM Records
WHERE StageID IN (SELECT StageID FROM Route WHERE ProductID = 1) AND SerialNumber = 'G001';
Для приведенных выше данных это дает мне:
| StageID | Result | RecordDate |
|--------- -------- ---------------------|
| 4 | 1 | 2019-03-16 00:00:00 |
| 2 | 1 | 2019-03-16 00:00:01 |
| 2 | 0 | 2019-03-16 00:00:02 |
|--------- -------- ---------------------|
Теперь сложная часть, где, к сожалению, мои знания SQL заканчиваются, заключается в том, что я хочу выполнить фильтрацию по идентификатору StageID, чтобы отображался только самый последний результат в таблице записей для этого идентификатора StageID и SerialNumber. Итак, в данном примере я хочу это:
| StageID | Result | RecordDate |
|--------- -------- ---------------------|
| 4 | 1 | 2019-03-16 00:00:00 |
| 2 | 0 | 2019-03-16 00:00:02 |
|--------- -------- ---------------------|
Фильтрация может быть выполнена по дате записи или, что еще проще, по Records.ID .
Но я не могу определить SQL, который позволил бы достичь этого, и я думаю, что это тот случай, когда я недостаточно знаю язык, чтобы сформулировать то, что я пытаюсь сделать.
Итак, мой вопрос: возможно ли отфильтровать эти результаты по самой последней записи для каждого StageID?
Я играл с параметрами GROUP BY безрезультатно.
Комментарии:
1. Пометьте вопрос базой данных, которую вы используете.
Ответ №1:
Использовать функции окна:
SELECT r.StageID, r.Result, r.RecordDate
FROM (SELECT r.*
ROW_NUMBER() OVER (PARTITION BY r.StageID ORDER BY r.RecordDate DESC) as seqnum
FROM Records r
) JOIN
Route ro
ON ro.StageID = r.StageID AND ro.ProductId = 1
WHERE r.SerialNumber = 'G001';
Или вы можете добавить
SELECT r.StageID, r.Result, r.RecordDate
FROM Records r
WHERE r.StageID IN (SELECT ro.StageID
FROM Route ro
WHERE ro.ProductID = 1
) AND
r.SerialNumber = 'G001' AND
r.RecordDate = (SELECT MAX(r2.RecordDate)
FROM records r2
WHERE r2.StageId = r.StageId
);
Комментарии:
1. Я был занят, пытаясь заставить ваш первый пример работать, из-за чего я получаю некоторые ошибки, когда вы опубликовали свой второй пример. Ваш второй пример мне намного проще понять, поскольку я ничего не знаю о функциях окна. Я понял ваш второй пример, и это улучшило мое понимание SQL, спасибо. Для понимания вашего первого примера мне потребуется немного больше работы, я рассмотрю оконные функции. Приветствия.
Ответ №2:
WITH cte
AS (SELECT StageID,
Result,
RecordDate,
Row_number()
OVER(
partition BY StageID
ORDER BY Record_Date DESC) AS rn
FROM table)
SELECT StageID,
Result,
RecordDate
FROM cte
WHERE rn = 1
ORDER BY StageID DESC