oba*_*sta 4 sql-server sql-server-2014
我需要根据以前的记录返回 0 或 1。示例表:
DECLARE @x TABLE(ProductID INT, Failed bit, SampleDate date, LevelCode int);
INSERT @x VALUES
(101, 0, '20151201', 1),
(101, 1, '20151205', 2),
(101, 0, '20151206', 3),
(101, 1, '20151208', 2),
(102, 1, '20151202', 1),
(102, 0, '20151204', 2),
(102, 0, '20151205', 3),
(103, 0, '20160101', 1),
(103, 1, '20160102', 2),
(103, 0, '20160103', 2),
(104, 0, '20160101', 1),
(104, 0, '20160102', 2),
(104, 0, '20160103', 3);
Run Code Online (Sandbox Code Playgroud)
我们在最后一条记录上唯一关心的是LevelCode(即每个ProductID 的最后一条记录)。最后一条记录是否通过/失败无关紧要。然后,我们查看该 ProductID 的所有其他记录(因此是最后一条记录之前的所有记录),如果出现与最后一条记录相同的 LevelCode 失败,我们将 IsLastRunSameLevelAsPreviousRun 设置为 1,否则为 0:
ProductID IsLastRunSameLevelAsPreviousRun
101 1
102 0
103 1
104 0
Run Code Online (Sandbox Code Playgroud)
如果有一个没有失败ProductID
的IsLastRunSameLevelAsPreviousRun
应该返回0。
非常感谢任何帮助或提示。
WITH cte AS
(
SELECT
ProductID,
SampleDate,
MaxSampleDate = MAX(SampleDate) OVER (PARTITION BY ProductID),
PrevFailed = LAG(Failed, 1, 0) OVER (PARTITION BY ProductID, LevelCode
ORDER BY SampleDate)
FROM
@x
)
SELECT
ProductID,
IsLastRunSameLevelAsPreviousRun = PrevFailed
FROM
cte
WHERE
SampleDate = MaxSampleDate
;
Run Code Online (Sandbox Code Playgroud)
在cte
获得先前的Failed
为相同的状态LevelCode
针对每个内的每个行ProductID
组,返回0时不存在匹配的行。它还计算每个组中的最后日期,以便稍后使用它来确定组中的最后一行。
这是它返回的内容:
ProductID SampleDate MaxSampleDate PrevFailed
--------- ---------- ------------- ----------
101 2015-12-01 2015-12-08 0
101 2015-12-05 2015-12-08 0
101 2015-12-08 2015-12-08 1
101 2015-12-06 2015-12-08 0
102 2015-12-02 2015-12-05 0
102 2015-12-04 2015-12-05 0
102 2015-12-05 2015-12-05 0
103 2016-01-01 2016-01-03 0
103 2016-01-02 2016-01-03 0
103 2016-01-03 2016-01-03 1
104 2016-01-01 2016-01-03 0
104 2016-01-02 2016-01-03 0
104 2016-01-03 2016-01-03 0
Run Code Online (Sandbox Code Playgroud)
主要选择在使用基本上只是需要每个组的最后一排SampleDate = MaxSampleDate
过滤器,只拉ProductID
和PrevFailed
也改名后者IsLastRunSameLevelAsPreviousRun
,使最终输出变成你想要的东西:
ProductID IsLastRunSameLevelAsPreviousRun
--------- -------------------------------
101 1
102 0
103 1
104 0
Run Code Online (Sandbox Code Playgroud)
一种方法是使用ROW_NUMBER
两次。
首先对由ProductID
( CTE_RowNumbersAll
)分区的表的所有行进行编号,并仅获取每个ProductID
( CTE_LastAll
)的最后一行。
然后编号所有失败的行 ( CTE_RowNumbersFailed
) 并获取每个失败的行ProductID
( CTE_LastFailed
)。
最后将LEFT JOIN
中间结果放在一起并用于CASE
比较LevelCode
值。
更新
根据您的最后一条评论,我更改了查询。CTE_RowNumbersFailed
现在基于CTE_RowNumbersAll
并且有一个额外的过滤器rnAll > 1
可以从考虑中删除最后一行。
WITH
CTE_RowNumbersAll
AS
(
SELECT
ProductID
,Failed
,SampleDate
,LevelCode
,ROW_NUMBER() OVER(PARTITION BY ProductID ORDER BY SampleDate DESC) AS rnAll
FROM @x
)
,CTE_LastAll
AS
(
SELECT
ProductID
,LevelCode
FROM CTE_RowNumbersAll
WHERE rnAll = 1
)
,CTE_RowNumbersFailed
AS
(
SELECT
ProductID
,Failed
,SampleDate
,LevelCode
,ROW_NUMBER() OVER(PARTITION BY ProductID ORDER BY SampleDate DESC) AS rnFailed
FROM CTE_RowNumbersAll
WHERE
Failed = 1
AND rnAll > 1
)
,CTE_LastFailed
AS
(
SELECT
ProductID
,LevelCode
FROM CTE_RowNumbersFailed
WHERE rnFailed = 1
)
SELECT
CTE_LastAll.ProductID
,CASE WHEN CTE_LastAll.LevelCode = CTE_LastFailed.LevelCode
THEN 1 ELSE 0 END AS IsLastRunSameLevelAsPreviousRun
FROM
CTE_LastAll
LEFT JOIN CTE_LastFailed ON CTE_LastFailed.ProductID = CTE_LastAll.ProductID
ORDER BY CTE_LastAll.ProductID;
Run Code Online (Sandbox Code Playgroud)
结果
+-----------+---------------------------------+
| ProductID | IsLastRunSameLevelAsPreviousRun |
+-----------+---------------------------------+
| 101 | 1 |
| 102 | 0 |
| 103 | 1 |
| 104 | 0 |
+-----------+---------------------------------+
Run Code Online (Sandbox Code Playgroud)