sql-server – 将每日时间表分组为[开始日期;结束日期]与工作日
发布时间:2021-01-10 10:34:27 所属栏目:MsSql教程 来源:网络整理
导读:我需要在两个系统之间转换数据. 第一个系统将日程表存储为日期的简单列表.计划中包含的每个日期都是一行. 日期顺序(周末,公众假期和更长的停顿)可能存在各种差距,一周中的某些日子可能会被排除在日程表之外.根本没有差距,甚至可以包括周末.时间表最长可达2年.
这是一个简单的策略,可用于短于或长于一周的序列(替换任何其他数字的常数7的任何出现,以及从DayNo的MODULUS x而不是DATEPART(wk)计算的dowBit),直到32. SET DATEFIRST 1 -- Make Monday weekday=1 -- Get the minimum information needed to calculate sequences DECLARE @Days TABLE (ContractID int NOT NULL,DayNo int NOT NULL,dowBit int NOT NULL,PRIMARY KEY (ContractID,DayNo)); INSERT INTO @Days SELECT ContractID,CAST(CAST(dt AS datetime) AS int) AS DayNo,dt)-1) AS dowBit FROM @Src DECLARE @RangeStartFirstPass TABLE (ContractID int NOT NULL,DayNo)) -- Calculate,from the above list,which days are not present in the previous 7 INSERT INTO @RangeStartFirstPass SELECT r.ContractID,r.DayNo FROM @Days r LEFT JOIN @Days pr ON (pr.ContractID = r.ContractID AND pr.DayNo BETWEEN r.DayNo-7 AND r.DayNo-1) -- Last 7 days GROUP BY r.ContractID,r.DayNo,r.dowBit HAVING r.dowBit & COALESCE(SUM(pr.dowBit),0) = 0 -- Update the previous list with all days that occur right after a missing day INSERT INTO @RangeStartFirstPass SELECT * FROM ( SELECT DISTINCT ContractID,(SELECT MIN(DayNo) FROM @Days WHERE ContractID = d.ContractID AND DayNo > d.DayNo + 7) AS DayNo FROM @Days d WHERE NOT EXISTS (SELECT 1 FROM @Days WHERE ContractID = d.ContractID AND DayNo = d.DayNo + 7) ) d WHERE DayNo IS NOT NULL AND NOT EXISTS (SELECT 1 FROM @RangeStartFirstPass WHERE ContractID = d.ContractID AND DayNo = d.DayNo) DECLARE @RangeStart TABLE (ContractID int NOT NULL,DayNo)); -- Fetch the first sequence for each contract INSERT INTO @RangeStart SELECT ContractID,MIN(DayNo) FROM @RangeStartFirstPass GROUP BY ContractID -- Add to the list above the next sequence for each contract,until all are added -- (ensure no sequence is added with less than 7 days) WHILE @@ROWCOUNT > 0 INSERT INTO @RangeStart SELECT f.ContractID,MIN(f.DayNo) FROM (SELECT ContractID,MAX(DayNo) AS DayNo FROM @RangeStart GROUP BY ContractID) s JOIN @RangeStartFirstPass f ON (f.ContractID = s.ContractID AND f.DayNo > s.DayNo + 7) GROUP BY f.ContractID -- Summarise results SELECT ContractID,CASE WHEN WeekDays & 64 > 0 THEN 'Sun,' ELSE '' END + CASE WHEN WeekDays & 1 > 0 THEN 'Mon,' ELSE '' END + CASE WHEN WeekDays & 2 > 0 THEN 'Tue,' ELSE '' END + CASE WHEN WeekDays & 4 > 0 THEN 'Wed,' ELSE '' END + CASE WHEN WeekDays & 8 > 0 THEN 'Thu,' ELSE '' END + CASE WHEN WeekDays & 16 > 0 THEN 'Fri,' ELSE '' END + CASE WHEN WeekDays & 32 > 0 THEN 'Sat,' ELSE '' END AS WeekDays FROM ( SELECT r.ContractID,MIN(d.dt) AS StartDT,MAX(d.dt) AS EndDT,COUNT(*) AS DayCount,SUM(DISTINCT d.dowBit) AS WeekDays FROM (SELECT *,COALESCE((SELECT MIN(DayNo) FROM @RangeStart WHERE ContractID = rs.ContractID AND DayNo > rs.DayNo),999999) AS DayEnd FROM @RangeStart rs) r JOIN @Days d ON (d.ContractID = r.ContractID AND d.DayNo BETWEEN r.DayNo AND r.DayEnd-1) GROUP BY r.ContractID,r.DayNo ) d ORDER BY ContractID,StartDT (编辑:威海站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |