0

给定一个包含以下数据的表(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,但后来被状态为 1 的记录 ID 4 取代。如果在稍后的某个时间点为 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.Id 的值。我知道我可以通过 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)

我可以在这里看到的唯一缺点是,如果有两条时间戳完全相同的记录,那么它将在结果集中出现两次。例如,如果 Id 21 被复制为 22,那么它将出现两次。这不是一个真正的问题,因为在现实中,时间戳总是唯一的。

4

2 回答 2

1

这是关于你所追求的吗?

declare @tableB table (recid varchar(6), dt datetime)
insert @tableB
select recid, max(dt) from @tableA
where stat = 1
group by recid

这将为您创建一个包含所有“1”及其最大日期的表格。

select * from @tableA a
left join @tableB b on a.recid = b.recid
where a.stat = 2 and a.dt > isnull(b.dt, '1753-01-01')

这将显示来自 A 的所有记录,除了后面有 B 的记录。

于 2011-08-05T04:50:37.603 回答
1
WITH ranked AS (
  SELECT
    *,
    rn = ROW_NUMBER() OVER (PARTITION BY RecId ORDER BY Dt DESC)
  FROM TableA
)
SELECT
  r1.Id,
  r1.Dt,
  r1.Stat,
  r1.RecId
FROM ranked r1
  INNER JOIN ranked r2 ON r1.RecId = r2.RecId AND r2.rn = 1
WHERE r1.Stat = 2

问题更新后更新

WITH ranked AS (
  SELECT
    *,
    rn = ROW_NUMBER() OVER (PARTITION BY RecId ORDER BY Dt DESC)
  FROM TableA
)
SELECT
  Id,
  Dt,
  Stat,
  RecId
FROM ranked
WHERE Stat = 2 AND rn = 1
于 2011-08-05T04:54:20.723 回答