私の以前の編集は少し混乱していました。うまくいけば、これで解決します...
TL/DR -- 2 つのスクリプト ブロックをコピーして実行するだけで明らかになります。
カスケード データについて質問があります。基本的に、いくつかの事前定義された条件 (以下) に従って、ウォーターフォール効果でデータを下に移動しようとしています。私は 18 のシナリオのうち 15 を解決し、残りの 3 つのシナリオ (GID の 9、10、および 18 のシナリオ) を手伝っています。
ちょっとした見方をすると、私が取り組んでいるシステムでは、データは継続的にシステムにインポートされます。データはまばらで、完全なデータ セットを再構成してインポート プロセスを完了する作業を行っています。システム内のデータの形状、または提供されているデータの形状をほとんど制御できません:-/
最終的な問題は、以下の 5 つのカスケード ルールを満たすにはどうすればよいか、または、以下のスクリプトで提供したテスト ケース 18 をどのように解決するかということです。
カスケード ルール
この簡略化されたシナリオでは、カスケードの「ルール」は次のとおりです。
- データは同じグループ内でのみカスケードされます (
GID
) - データのグループは 1 から順に並べられます (
Seq
) IsLive
列は 1 または 0 のいずれかになります- 次に、別の値またはnull以外の値が
IsLive = 1
見つかるまで、データを行の下に移動しますIsLive = 1
IsLive = 0
- 次に、別の値
IsLive = 0
にヒットするまで、データを行の下に移動しIsLive = 0
ます。
注: 私のスクリプトは単純化された例ですが、完全なシナリオではN
、カスケードする必要がある列があります。
ソリューション ノート
以下の SQL を実行すると、Input、Output - CTE の結果、Expected - 期待される結果、Result - 合格/不合格の 3 つの列が表示されます。サンプル テーブルを作成し、実行するだけでテスト ケースを説明するスクリプトを含めました。
- 以下のテストケーススクリプトにはサンプルデータがあります
- テスト ケース スクリプトには、正しい期待値のために追加した列があります。(INSERT スクリプトで GID=18 を探します。)
誰かが助けてくれることを願っています。そうでない場合は、SQL CLR SP ソリューションに頼る必要があるかもしれません。また、私はこの解決策に縛られていません。私の解決策を完全に破棄して、何か新しいものを考え出すこともできます。
テストケース
DECLARE @Test TABLE (GID int, Seq int, IsLive bit,
Eff date,
Name varchar(50),
Expected varchar(50)) -- expected val should help debug!
INSERT INTO @Test VALUES (1, 1, 1, '01-08-2012', 'RTS', 'RTS')
INSERT INTO @Test VALUES (1, 2, 0, '01-09-2012', 'RTA', 'RTA')
INSERT INTO @Test VALUES (1, 3, 1, '01-10-2012', 'FSA', 'RTA')
INSERT INTO @Test VALUES (1, 4, 0, '01-11-2012', NULL, 'RTA')
INSERT INTO @Test VALUES (1, 5, 1, '01-12-2012', 'FSA', 'RTA')
INSERT INTO @Test VALUES (2, 1, 1, '01-08-2012', 'RTS', 'RTS')
INSERT INTO @Test VALUES (2, 2, 0, '01-09-2012', 'RTA', 'RTA')
INSERT INTO @Test VALUES (2, 3, 1, '01-10-2012', 'FSA', 'RTA')
INSERT INTO @Test VALUES (2, 4, 0, '01-11-2012', 'GSM', 'GSM')
INSERT INTO @Test VALUES (2, 5, 1, '01-12-2012', 'FSA', 'GSM')
INSERT INTO @Test VALUES (3, 1, 1, '01-01-2012', 'FSA', 'FSA')
INSERT INTO @Test VALUES (3, 2, 0, '01-02-2012', NULL, 'FSA')
INSERT INTO @Test VALUES (4, 1, 1, '01-01-2012', NULL, NULL)
INSERT INTO @Test VALUES (4, 2, 0, '01-02-2012', 'FSA', 'FSA')
INSERT INTO @Test VALUES (4, 3, 0, '01-03-2012', NULL, 'FSA')
INSERT INTO @Test VALUES (5, 1, 0, '01-01-2012', NULL, NULL)
INSERT INTO @Test VALUES (5, 2, 1, '01-02-2012', 'LSI', 'LSI')
INSERT INTO @Test VALUES (5, 3, 0, '01-03-2012', NULL, 'LSI')
INSERT INTO @Test VALUES (6, 1, 1, '01-01-2012', NULL, NULL)
INSERT INTO @Test VALUES (6, 2, 0, '01-02-2012', 'LSI', 'LSI')
INSERT INTO @Test VALUES (6, 3, 1, '01-03-2012', NULL, 'LSI')
INSERT INTO @Test VALUES (7, 1, 1, '01-01-2012', 'FSA', 'FSA')
INSERT INTO @Test VALUES (7, 2, 0, '01-02-2012', NULL, 'FSA')
INSERT INTO @Test VALUES (7, 3, 1, '01-03-2012', 'RTA', 'RTA')
INSERT INTO @Test VALUES (8, 1, 1, '01-01-2012', 'FSA', 'FSA')
INSERT INTO @Test VALUES (8, 2, 0, '01-02-2012', NULL, 'FSA')
INSERT INTO @Test VALUES (8, 3, 1, '01-03-2012', NULL, NULL)
INSERT INTO @Test VALUES (9, 1, 1, '01-01-2012', 'FSA', 'FSA')
INSERT INTO @Test VALUES (9, 2, 1, '01-02-2012', NULL, NULL)
INSERT INTO @Test VALUES (9, 3, 1, '01-03-2012', 'RTS', 'RTS')
INSERT INTO @Test VALUES (10, 1, 1, '01-01-2012', 'FSA','FSA')
INSERT INTO @Test VALUES (10, 2, 1, '01-02-2012', 'GSM','GSM')
INSERT INTO @Test VALUES (10, 3, 1, '01-03-2012', 'RTS','RTS')
INSERT INTO @Test VALUES (11, 1, 0, '01-01-2012', 'NOP','NOP')
INSERT INTO @Test VALUES (11, 2, 1, '01-02-2012', 'TAP','NOP')
INSERT INTO @Test VALUES (11, 3, 1, '01-03-2012', 'STG','NOP')
INSERT INTO @Test VALUES (12, 1, 1, '01-01-2012', 'RTS','RTS')
INSERT INTO @Test VALUES (12, 2, 0, '01-02-2012', 'RTM','RTM')
INSERT INTO @Test VALUES (12, 3, 1, '01-03-2012', 'LSA','RTM')
INSERT INTO @Test VALUES (12, 4, 1, '01-03-2012', 'LSA','RTM')
INSERT INTO @Test VALUES (12, 5, 1, '01-03-2012', 'GSM','RTM')
INSERT INTO @Test VALUES (13, 1, 1, '01-08-2012', 'BAR','BAR')
INSERT INTO @Test VALUES (13, 2, 0, '01-09-2012', NULL, 'BAR')
INSERT INTO @Test VALUES (13, 3, 1, '01-10-2012', 'TST','TST')
INSERT INTO @Test VALUES (14, 1, 1, '01-08-2012', 'BAR','BAR')
INSERT INTO @Test VALUES (14, 2, 0, '01-09-2012', 'GIP','GIP')
INSERT INTO @Test VALUES (14, 3, 1, '01-10-2012', 'TST','GIP')
INSERT INTO @Test VALUES (15, 1, 1, '01-01-2012', 'BAR','BAR')
INSERT INTO @Test VALUES (15, 2, 0, '01-02-2012', 'BAR','BAR')
INSERT INTO @Test VALUES (15, 3, 1, '01-02-2012', 'BAR','BAR')
INSERT INTO @Test VALUES (15, 4, 1, '01-02-2012', 'GYM','BAR')
INSERT INTO @Test VALUES (16, 1, 1, '01-02-2012', 'BAR','BAR')
INSERT INTO @Test VALUES (16, 2, 0, '01-03-2012', NULL, 'BAR')
INSERT INTO @Test VALUES (16, 3, 1, '01-03-2012', 'BAR','BAR')
INSERT INTO @Test VALUES (16, 4, 1, '01-03-2012', 'GYM','GYM')
INSERT INTO @Test VALUES (17, 1, 1, '01-02-2012', 'BAR', 'BAR')
INSERT INTO @Test VALUES (17, 2, 0, '01-03-2012', 'GIP', 'GIP')
INSERT INTO @Test VALUES (17, 3, 0, '01-03-2012', NULL, 'GIP')
INSERT INTO @Test VALUES (17, 4, 1, '01-03-2012', 'TST', 'GIP')
-- -------------------------------------------
-- Following is the GID=18 test case that fails
-- -------------------------------------------
INSERT INTO @Test VALUES (18, 1, 1, '01-02-2012', 'BAR', 'BAR')
INSERT INTO @Test VALUES (18, 2, 0, '01-03-2012', 'BAR', 'BAR')
INSERT INTO @Test VALUES (18, 3, 0, '01-03-2012', NULL, 'BAR')
INSERT INTO @Test VALUES (18, 4, 1, '01-03-2012', 'TST', 'BAR')
解決
DECLARE @PrevNonLiveSeq int = NULL
;WITH CTE AS (
SELECT T.GID, T.SEQ, T.IsLive, Expected
, Name AS Name
, CASE WHEN T.IsLive = 0 THEN T.SEQ ELSE NULL END As PrevNonLiveSeq
, CASE WHEN T.IsLive = 1 THEN T.SEQ ELSE NULL END As PrevLiveSeq
, NULL AS PerNonLiveSeqCalc
, NULL AS PerLiveSeqCalc
, 0 PrevSeq
, CAST(NULL AS varchar(50)) PrevName
FROM @Test T
WHERE T.Seq = 1
UNION ALL
SELECT Curr.GID, Curr.SEQ, Curr.IsLive, Curr.Expected
,CASE WHEN Curr.IsLive = 0 THEN ISNULL(Curr.Name, Prev.Name)
ELSE CASE WHEN PrevNonLive.Name IS NULL THEN
CASE WHEN Prev.Name <> PrevLive.Name THEN Prev.Name ELSE Curr.Name END
ELSE Prev.Name END
END
,CASE WHEN Curr.IsLive = 0 THEN Curr.SEQ ELSE Prev.PrevNonLiveSeq END As PrevNonLiveSeq
,CASE WHEN Curr.IsLive = 1 THEN Curr.SEQ ELSE Prev.PrevLiveSeq END As PrevLiveSeq
, ISNULL(Prev.PrevNonLiveSeq, Curr.SEQ) AS PerNonLiveSeqCalc
, ISNULL(Prev.PrevLiveSeq, Curr.SEQ) AS PerLiveSeqCalc
, Prev.Seq PrevSeq, Prev.Name PrevName
FROM CTE Prev
JOIN @Test Curr ON Curr.GID = Prev.GID AND Curr.SEQ = Prev.SEQ+1
JOIN @Test PrevNonLive ON Prev.GID = PrevNonLive.GID AND PrevNonLive.SEQ = ISNULL(Prev.PrevNonLiveSeq, Curr.SEQ)
JOIN @Test PrevLive ON Prev.GID = PrevLive.GID AND PrevLive.SEQ = ISNULL(Prev.PrevLiveSeq, Curr.SEQ)
)
SELECT CTE.GID, CTE.Seq, T.IsLive
, T.Name Input, CTE.Name [Output]
, CASE WHEN CTE.Name = CTE.Expected OR (CTE.Name IS NULL AND CTE.Expected IS NULL) THEN 'Pass' ELSE 'FAIL' END AS Result
, CTE.Expected
FROM CTE
INNER JOIN @Test T on CTE.GID = T.GID AND CTE.Seq = T.Seq
ORDER BY CTE.GID, CTE.Seq
結果
結果を得るには、コピーして SSMS で実行してください
ありがとう!