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のレコードを除いて、ステータスが2のすべてのレコードを返すにはどうすればよいですか。ただし、ステータスが2の後に1のレコードが続く(ステータスが2のレコードはこれ以上ありません)。

したがって、たとえば、過去にREC001のステータスが2であったため、クエリはREC002とREC003を返す必要がありますが、後日、ステータスが1のレコードID4に置き換えられました。後のある時点で、ステータス2のREC001に別のレコードが追加された場合、これは結果セットに再び存在するはずです(ステータス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'

どんなアイデアでも大歓迎です。

編集:私は与えられた2つの答えを試しました、そしてどちらも私が必要なものを正確に私に与えませんでしたが、彼らは確かに私を正しい方向に向けました。与えられた答えを使用して、私は私が必要とすることをしているように見える次のことを思いついた。

;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)

ここで確認できる唯一の欠点は、タイムスタンプがまったく同じ2つのレコードがある場合、結果セットに2回表示されることです。たとえば、Id 21が22として再現された場合、2回表示されます。実際には、タイムスタンプは常に一意であるため、これは実際の問題ではありません。

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')

これにより、後のBがあるレコードを除いて、Aのすべてのレコードが表示されます。

于 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 に答える