Учитывая таблицу (TableA), которая содержит следующие данные:
Id Date Status RecordId
1 01/06/11 2 REC001
2 01/06/11 2 REC002
3 01/06/11 2 REC003
4 01/07/11 1 REC001
Как я могу вернуть все записи со статусом 2, кроме записей с заданным RecordId, где за статусом 2 следует символзапись 1 на более позднюю дату (и больше нет записей с состоянием 2.
Так, например, запрос должен вернуть REC002 и REC003, так как REC001 имел статус 2 в прошлом, но этобыл заменен идентификатором записи 4 со статусом 1 на более позднюю дату. Если в какой-то более поздний момент времени для REC001 была добавлена еще одна запись со статусом 2, то она снова должна присутствовать в наборе результатов (при условииболее поздние записи со статусом 1).
Моя слабая попытка возиться с этим:
DECLARE @TableA TABLE
(
Id INT,
Dt DATETIME,
Stat INT,
RecId VARCHAR(6)
)
INSERT INTO @TableA
SELECT 1, DATEADD(day, -5, current_timestamp), 2, 'REC001'
UNION
SELECT 2, DATEADD(day, -4, current_timestamp), 2, 'REC002'
UNION
SELECT 3, DATEADD(day, -3, current_timestamp), 2, 'REC003'
UNION
SELECT 4, DATEADD(day, -2, current_timestamp), 1, 'REC001'
SELECT *
FROM @TableA t1
LEFT JOIN @TableA t2 ON t1.RecId = t2.RecId
WHERE t1.Stat = 2
AND (t1.Dt >= t2.Dt
AND t2.Stat != 1)
Это работает, но возвращает значения, где t1.Id = t2.То есть, я знаю, что могу исключить это с помощью предложения where, но если я добавлю еще несколько записей в таблицу, это снова не удастся. Например;
INSERT INTO @TableA
SELECT 1, DATEADD(day, -15, current_timestamp), 2, 'REC004'
UNION
SELECT 2, DATEADD(day, -14, current_timestamp), 2, 'REC002'
UNION
SELECT 3, DATEADD(day, -13, current_timestamp), 1, 'REC003'
UNION
SELECT 4, DATEADD(day, -12, current_timestamp), 1, 'REC001'
UNION
SELECT 11, DATEADD(day, -5, current_timestamp), 2, 'REC004'
UNION
SELECT 21, DATEADD(day, -4, current_timestamp), 2, 'REC002'
UNION
SELECT 31, DATEADD(day, -3, current_timestamp), 1, 'REC003'
UNION
SELECT 41, DATEADD(day, -2, current_timestamp), 1, 'REC001'
Любые идеи приветствуются.
РЕДАКТИРОВАТЬ: Я попробовал два ответа, и хотя ни один из них не дал мне именно то, что мне нужно, они, безусловно, указали мне в правильном направлении.Используя приведенные ответы, я пришел к следующему, которое, кажется, выполняет то, что мне нужно:
;WITH lastSuccess(recid, dt) AS (
select recid, max(dt) from @tableA
where stat = 1
group by recid
),
lastFailure(recid, dt) AS (
select recid, max(dt) from @tableA
where stat = 2
group by recid
)
select a.* from @tablea a
-- Limit results to those that include a failure
INNER JOIN lastFailure lf ON lf.recid = a.recid AND lf.dt = a.dt
-- If the recid also has a success, show this along with it's latest success date
LEFT JOIN lastSuccess ls ON ls.recid = lf.recid
-- Limit records to where last failure is > last success or where there is no last success.
WHERE (lf.dt > ls.dt OR ls.dt IS NULL)
Единственный недостаток, который я могу видеть здесь, - это наличие двух записей с одинаковой отметкой времени, тогда этов результате установить дважды.Например, если идентификатор 21 был повторен как 22 тогда, он появится дважды.Это не настоящая проблема, так как в действительности метка времени всегда будет уникальной.