在最近询问之前,我已经成功建立了一个查询,该查询可以计算每个用户日志的间隔。 CTE使用ROW_NUMBER()按用户ID列出每个用户日志,然后在第二个CTE中,它自动加入“ RN ID + 1”,从而对“ INIx日期-FINx-1”进行“递归”计算,稍后我添加视觉帮助指示器。按原样运行查询,它几乎可以正确返回几乎每一行,但是我注意到在某些情况下,第一个顺序日志被列为“ NOSEQ”(无顺序),因为我的指示器仅将“ 1”作为连续条件。
其中RN = 5时是连续的,但由于它使用以下日志进行计算,因此不符合要求。我不知道我是否缺少某些东西,或者我必须重新开始...感谢查询逻辑方面的任何帮助。 (考虑到我仅限于SQL Server 2008 sintax)
IF NOT EXISTS (
select * from sysobjects where name='INF_LIC' and xtype='U'
) CREATE TABLE INF_LIC (
[PER_PRO_ID_HR_INI_FIN] NVARCHAR(57)
);
INSERT INTO INF_LIC VALUES
(N'201811;P1;2018-11-23 00:00:00.000;2018-11-23 00:00:00.000'),
(N'201810;P1;2018-10-25 00:00:00.000;2018-10-26 00:00:00.000'),
(N'201809;P1;2018-09-28 00:00:00.000;2018-09-28 00:00:00.000'),
(N'201808;P1;2018-08-31 00:00:00.000;2018-09-05 00:00:00.000'),
(N'201807;P1;2018-07-05 00:00:00.000;2018-07-25 00:00:00.000'),
(N'201806;P1;2018-06-14 00:00:00.000;2018-07-04 00:00:00.000'),
(N'201805;P1;2018-05-25 00:00:00.000;2018-06-13 00:00:00.000'),
(N'201805;P1;2018-05-10 00:00:00.000;2018-05-24 00:00:00.000'),
(N'201804;P1;2018-04-25 00:00:00.000;2018-05-09 00:00:00.000');
;WITH CTE AS(
-- LIST EVERY RECORD
SELECT ID, CAST(INI AS DATETIME) AS INI, CAST(FIN AS DATETIME) AS FIN,
RN = ROW_NUMBER()OVER(PARTITION BY ID ORDER BY CAST(FIN AS DATETIME) DESC)
FROM INF_LIC
WHERE PER_PRO > 201712
), CTE2 AS(
-- CALCULATE DATEDIFF
SELECT T.*,
-- DATEDIFF BETWEEN INIn - FINn-1
DD = CASE WHEN DATEDIFF(DD,T.FIN,T2.INI) IS NULL THEN 0 ELSE DATEDIFF(DD,T2.INI,T.FIN) END
FROM CTE
-- LEFT JOIN ON EQUAL ID's AND RN = RN+1
LEFT JOIN CTE T2 ON T.RN = T2.RN + 1 AND T.ID = T2.ID AND T.RN <> T2.RN
), CTE3 AS(
SELECT ID, INI, FIN, RN, ABS(DD) AS DD,
-- INDICATOR, IF -1 ITS 'SEQ', NULL MARKS THE NEWEST LOG 'FIRSTLOG' ELSE IT'S NOT SEQUENTIAL
IND = (CASE WHEN DD = -1 THEN 'SEQ'
WHEN DD = 0 THEN 'FIRSTLOG'
ELSE 'NOSEQ'
END)
FROM CTE2
), CTE4 AS(
SELECT ID, INI, FIN, RN, DD, IND
FROM CTE3
GROUP BY ID, INI, FIN, RN, DD, IND
)
SELECT * FROM CTE4
ORDER BY ID, RN ASC
答案 0 :(得分:0)
尚不清楚您为什么相信记录5是连续的。问题中的SQL暗示顺序的定义是上一条记录的ini
与该记录的fin
相隔1天,这是事实。
但是,鉴于这些列名,这是一个可疑的定义。我怀疑您想定义ind
以便当该记录的fin
与下一条记录的ini
相隔1天时是连续的。如果是这样,那么您可能想要这样做:
WITH CTE AS(
-- LIST EVERY RECORD
SELECT ID, CAST(INI AS DATETIME) AS INI, CAST(FIN AS DATETIME) AS FIN,
RN = ROW_NUMBER()OVER(PARTITION BY ID ORDER BY CAST(FIN AS DATETIME) DESC)
FROM INF_LIC
WHERE PER_PRO > 201712
), CTE2 AS(
-- CALCULATE DATEDIFF
SELECT T.*,
-- DATEDIFF BETWEEN INIn - FINn-1
DD = CASE WHEN DATEDIFF(DD,T2.FIN,T.INI) IS NULL THEN 0 ELSE DATEDIFF(DD,T.INI,T2.FIN) END
FROM CTE T
-- LEFT JOIN ON EQUAL ID's AND RN = RN+1
LEFT JOIN CTE T2 ON T.RN = T2.RN - 1 AND T.ID = T2.ID
), CTE3 AS(
SELECT ID, INI, FIN, RN, ABS(DD) AS DD,
-- INDICATOR, IF -1 ITS 'SEQ', NULL MARKS THE NEWEST LOG 'FIRSTLOG' ELSE IT'S NOT SEQUENTIAL
IND = (CASE WHEN DD in (0, -1) THEN 'SEQ'
WHEN RN = 1 THEN 'FIRSTLOG'
ELSE 'NOSEQ'
END)
FROM CTE2
), CTE4 AS(
SELECT ID, INI, FIN, RN, DD, IND
FROM CTE3
GROUP BY ID, INI, FIN, RN, DD, IND
)
SELECT * FROM CTE4
ORDER BY ID, RN ASC
相关更改为:
LEFT JOIN CTE T2 ON T.RN = T2.RN - 1 AND T.ID = T2.ID
该联接现在为T2.RN
减1:您需要减去下一条记录的行号才能获取,而不是添加,并且:
IND = (CASE WHEN DD in (0, -1) THEN 'SEQ'
WHEN RN = 1 THEN 'FIRSTLOG'
ELSE 'NOSEQ'
END)
由于您已经在进行行编号,因此最好使用明显的FIRSTLOG定义。由于此连接顺序现在从原始假设开始倒退,因此DD
为0意味着它是最后一个记录,而不是第一个记录,因此它会稍微扩展SEQ的定义。