我有一个看起来像这样的表(没有尝试列):
Account Status Date Attempt(*)
A In_PROGRESS 12/12/2017 1
A ERROR 13/12/2017 1
A SUCCESS 15/12/2017 2
B ERROR 10/12/2017 1
B SUCCESS 13/12/2017 2
C IN_PROGRESS 11/12/2017 1
C ERROR 13/12/2017 1
C ERROR 14/12/2017 2
C IN_PROGRESS 15/12/2017 3
我想获得Attempt(*)列。 ERROR和SUCCESS状态是最终状态。例如,对于帐户C,我们有第一次尝试产生ERROR,第二次尝试产生ERROR,第三次尝试产生IN_PROGRESS。
我知道RANK()因为短暂的状态而无法工作,并且不能正常工作。例如,如果我要去:
RANK()OVER(按帐户ORDER按日期ASC划分)
我会得到:
Account Status Date Attempt(*)
A In_PROGRESS 12/12/2017 1
A ERROR 13/12/2017 2
A SUCCESS 15/12/2017 3
B ERROR 10/12/2017 1
B SUCCESS 13/12/2017 2
C IN_PROGRESS 11/12/2017 1
C ERROR 13/12/2017 2
C ERROR 14/12/2017 3
C IN_PROGRESS 15/12/2017 4
不考虑暂时状态。我会使用第二个表中的结果创建一个新列来获得所需的结果,sudo代码将类似于:
New_Attempt [n] =如果尝试(*)= 1则为1其他(如果尝试(*)> 1且状态[n-1]在(错误,成功)中则尝试[n-1] + 1其他尝试[N-1])
其中' n'是行号。
我对SQL比较陌生,我研究过其他排名功能,比如NTILE和DENSE_RANK,但我仍然无法找到一种方法。
P.S。我在SQL Server Management Studio 2008中使用T-SQL
谢谢! :)
答案 0 :(得分:3)
对于每一行,计算同一帐户中不是IN_PROGRESS
的所有先前行,并将1添加到结果中。
以C
帐户为例:
Account Status Date Attempt (expected values)
------- ----------- ---------- -------
C IN_PROGRESS 11/12/2017 1
C ERROR 13/12/2017 1
C ERROR 14/12/2017 2
C IN_PROGRESS 15/12/2017 3
显然,第一行之前没有行,这意味着也有0个非IN_PROGRESS
行。拿下并添加1,你将得到1作为Attempt
的值。第二行也是如此:在它之前仍然没有非IN_PROGRESS
行,因此Attempt
也将为1。
现在对于第三行,您之前已经有一行ERROR
行,因此计数将为1,最后为Attempt
值,因此为2。
对于最后一行,它前面有两个非IN_PROGRESS
行(两个ERROR
行),因此计数为2,最终结果为3.
您可以看到上述说明中的所有值都与您指定的预期值相匹配。现在,如果在窗口聚合函数中使用ORDER BY(换句话说,如果您使用的是SQL Server 2012或更高版本),则可以实现逻辑:
SELECT
Account,
Status,
Date,
Attempt = 1 + COUNT(CASE WHEN Status <> 'IN_PROGRESS' THEN 1 END)
OVER (PARTITION BY Account
ORDER BY Date
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)
FROM
dbo.YourTable
;
这就是您可以在SQL Server 2008中使用的方法来解决缺少的功能:
SELECT
Account,
Status,
Date,
Attempt = 1 + (SELECT
COUNT(*)
FROM
dbo.YourTable AS sub
WHERE
sub.Account = main.Account
AND sub.Date < main.Date
AND sub.Status <> 'IN_PROGRESS')
FROM
dbo.YourTable AS main
;
注意:假设Date
唯一标识帐户中的行。
答案 1 :(得分:1)
这不是世界上最漂亮的查询,但它会为您提供我认为您想要的结果。基本上我只是按照IN_PROGRESS的规则结束了尝试的计数。我在示例集中添加了一些记录来证明功能。我还想指出,这种解决方案可能无法很好地扩展。因此,如果您的数据集很大,请注意。
CREATE TABLE #Test (Account char(1), [Status] varchar(50), [Date] datetime)
INSERT INTO #Test (Account, [Status], [Date])VALUES
('A', 'IN_PROGRESS', '12/12/2017'),
('A', 'ERROR', '12/13/2017'),
('A', 'SUCCESS', '12/15/2017'),
('A', 'IN_PROGRESS', '12/16/2017'),
('A', 'IN_PROGRESS', '12/17/2017'),
('B', 'ERROR', '12/10/2017'),
('B', 'SUCCESS', '12/13/2017'),
('B', 'IN_PROGRESS', '12/15/2017'),
('B', 'IN_PROGRESS', '12/17/2017'),
('C', 'IN_PROGRESS', '12/11/2017'),
('C', 'ERROR', '12/13/2017'),
('C', 'ERROR', '12/14/2017'),
('C', 'IN_PROGRESS', '12/15/2017'),
('C', 'ERROR', '12/16/2017'),
('C', 'ERROR', '12/17/2017')
SELECT
T1.Account,
T1.[Status],
T1.[Date],
1 + SUM(COALESCE(TC.Attempt, 0)) AS 'Attempt(*)'
FROM
#Test AS T1
OUTER APPLY
(
SELECT
1 AS 'Attempt'
FROM
#Test AS T2
WHERE
T2.Account = T1.Account
AND T2.[Date] < T1.[Date]
AND T2.[Date] > COALESCE((SELECT TOP 1 T3.[Date] FROM #Test AS T3 WHERE T3.Account = T1.Account AND T3.[Status] = 'IN_PROGRESS' AND T3.[Date] < T1.[Date] ORDER BY T3.[Date] DESC), '01/01/2017')
AND T2.Status <> 'IN_PROGRESS'
) AS TC
GROUP BY
T1.Account,
T1.[Status],
T1.[Date]
ORDER BY
T1.Account,
T1.[Date]
DROP TABLE #Test