Sql server 根据收到和确定的日期,计算每周末未固定索赔的数量

Sql server 根据收到和确定的日期,计算每周末未固定索赔的数量,sql-server,tsql,recursion,common-table-expression,datepart,Sql Server,Tsql,Recursion,Common Table Expression,Datepart,我有一个索赔表,其中保存了从客户处收到的索赔,如下所示 create table claims(id int identity(1,1), Reception_Date datetime, Fixing_Date datetime) 如果固定日期为空,则表示索赔未固定,否则为固定 我想创建一个存储过程,它返回给定年份的以下数据:返回的列是 周数 一周结束的日期是星期天 收到的索赔数 固定索赔数 该周结束时的非固定索赔数量 数据示例: insert into claims (recept

我有一个索赔表,其中保存了从客户处收到的索赔,如下所示

create table claims(id int identity(1,1), Reception_Date datetime, Fixing_Date datetime)
如果固定日期为空,则表示索赔未固定,否则为固定

我想创建一个存储过程,它返回给定年份的以下数据:返回的列是

周数

一周结束的日期是星期天

收到的索赔数

固定索赔数

该周结束时的非固定索赔数量

数据示例:

    insert into claims (reception_date,fixing_date)
values
('02/20/2019 16:15','01/03/2020 17:00'),('01/04/2020 16:15','01/06/2020 17:00'),
('01/09/2020 16:15','09/21/2020 17:00'),('01/10/2020 16:15','10/21/2020 17:00'),
('10/10/2020 16:15','10/25/2020 17:20'),('10/24/2020 16:15','10/29/2020 14:20'),
('10/10/2020 16:15',NULL),('10/30/2020 16:15','10/31/2020 17:20'),
('10/10/2020 16:15','01/11/2020 16:22'),('11/01/2020 16:15','10/17/2020 08:20'),
('02/11/2020 16:15',NULL),('03/11/2020 16:15','10/11/2020 08:00'),
('05/11/2020 16:15',NULL),('05/11/2020 16:15','06/11/2020 11:20'),
('06/11/2020 16:15',NULL)

我创建的过程如下,如果您有更高性能的解决方案,请添加它


不要在每次执行时重新计算周表,而是构建一个永久的日期表并重用它。在我这边,您的查询平均需要140ms,而永久日期表则需要6ms

另外,不要过于依赖隐式转换,DATE-to-DATETIME将被隐式转换,从而降低查询速度。它还可能使您的查询忽略索引并导致表扫描

这是一个基本的日期表填充脚本,对于这个演示,我把它作为一个临时表,最好将它创建为一个实际的索引表

DECLARE @StartDate DATETIME = '2020-01-01 00:00:00'
DECLARE @EndDate DATETIME = '2021-01-01 00:00:00'

IF OBJECT_ID('tempdb..#Dates') IS NOT NULL DROP TABLE #Dates
CREATE TABLE #Dates (
    DateKey INT,
    WeekId INT,
    WeekStartDate DATE,
    StartDate DATETIME,
    EndDate DATETIME,
    DayNumber INT
)

WHILE (@StartDate < @EndDate)
BEGIN

INSERT INTO #Dates VALUES (FORMAT(@StartDate,'yyyyMMdd'), 
       DATEPART(WEEK,@StartDate),      
       DATEADD(DAY , 7-DATEPART(WEEKDAY,@StartDate),@StartDate),
       @StartDate,
       DATEADD(SECOND,-1,DATEADD(DAY,1,@StartDate)),
       DATEPART(WEEKDAY,@StartDate))

SET @StartDate = DATEADD(DAY,1,@StartDate)

END
一旦你有了dates表,你就可以开始利用它了,这个查询平均运行4到6毫秒

 DECLARE @year INT = 2020
 DECLARE @ClaimStartDate DATETIME = CONVERT(VARCHAR(4),@year)+'-Jan-01'
 DECLARE @ClaimEndDate DATETIME = DATEADD(SECOND,-1,DATEADD(YEAR,1,@ClaimStartDate))
 
 ;WITH WeekBase
 AS
 (SELECT D.WeekStartDate,
         D.WeekId
 FROM #Dates D
 WHERE D.StartDate BETWEEN @ClaimStartDate AND @ClaimEndDate
 GROUP BY D.WeekStartDate,
          D.WeekId),
 NotFixed
 AS
 (SELECT d.WeekStartDate,
       COUNT(1) NotFixedCount
 FROM WeekBase d
     INNER JOIN #CLAIMS ON reception_date < d.WeekStartDate
                        AND reception_date IS NOT NULL
                        AND (fixing_date IS NULL OR fixing_date > d.WeekStartDate)
 GROUP BY d.WeekStartDate),
 Fix
 AS 
 (SELECT D.WeekStartDate AS WeekStartDate,
         COUNT(1) AS FixedCount
 FROM #Dates D
      INNER JOIN #Claims C ON C.fixing_date BETWEEN D.StartDate AND D.EndDate
 WHERE D.StartDate BETWEEN @ClaimStartDate AND @ClaimEndDate
 GROUP BY D.WeekStartDate),
 Received
 AS
 (SELECT D.WeekStartDate AS WeekStartDate,
         COUNT(1) AS ReceivedCount
 FROM #Dates D
      INNER JOIN #Claims C ON C.reception_date BETWEEN D.StartDate AND D.EndDate
 WHERE D.StartDate BETWEEN @ClaimStartDate AND @ClaimEndDate
 GROUP BY D.WeekStartDate)
 SELECT D.WeekStartDate AS WeekStartDate,
        D.WeekId AS W,
        ISNULL(REC.ReceivedCount,0) AS Received,
       ISNULL(FIX.FixedCount,0) AS Fixed,
       ISNULL(NF.NotFixedCount,0) AS NotFixed
 FROM WeekBase D
      LEFT JOIN Received REC ON REC.WeekStartDate = D.WeekStartDate
     LEFT JOIN Fix FIX ON FIX.WeekStartDate = D.WeekStartDate
     LEFT JOIN NotFixed NF ON NF.WeekStartDate = D.WeekStartDate     

这不是一个博客。
 DECLARE @year INT = 2020
 DECLARE @ClaimStartDate DATETIME = CONVERT(VARCHAR(4),@year)+'-Jan-01'
 DECLARE @ClaimEndDate DATETIME = DATEADD(SECOND,-1,DATEADD(YEAR,1,@ClaimStartDate))
 
 ;WITH WeekBase
 AS
 (SELECT D.WeekStartDate,
         D.WeekId
 FROM #Dates D
 WHERE D.StartDate BETWEEN @ClaimStartDate AND @ClaimEndDate
 GROUP BY D.WeekStartDate,
          D.WeekId),
 NotFixed
 AS
 (SELECT d.WeekStartDate,
       COUNT(1) NotFixedCount
 FROM WeekBase d
     INNER JOIN #CLAIMS ON reception_date < d.WeekStartDate
                        AND reception_date IS NOT NULL
                        AND (fixing_date IS NULL OR fixing_date > d.WeekStartDate)
 GROUP BY d.WeekStartDate),
 Fix
 AS 
 (SELECT D.WeekStartDate AS WeekStartDate,
         COUNT(1) AS FixedCount
 FROM #Dates D
      INNER JOIN #Claims C ON C.fixing_date BETWEEN D.StartDate AND D.EndDate
 WHERE D.StartDate BETWEEN @ClaimStartDate AND @ClaimEndDate
 GROUP BY D.WeekStartDate),
 Received
 AS
 (SELECT D.WeekStartDate AS WeekStartDate,
         COUNT(1) AS ReceivedCount
 FROM #Dates D
      INNER JOIN #Claims C ON C.reception_date BETWEEN D.StartDate AND D.EndDate
 WHERE D.StartDate BETWEEN @ClaimStartDate AND @ClaimEndDate
 GROUP BY D.WeekStartDate)
 SELECT D.WeekStartDate AS WeekStartDate,
        D.WeekId AS W,
        ISNULL(REC.ReceivedCount,0) AS Received,
       ISNULL(FIX.FixedCount,0) AS Fixed,
       ISNULL(NF.NotFixedCount,0) AS NotFixed
 FROM WeekBase D
      LEFT JOIN Received REC ON REC.WeekStartDate = D.WeekStartDate
     LEFT JOIN Fix FIX ON FIX.WeekStartDate = D.WeekStartDate
     LEFT JOIN NotFixed NF ON NF.WeekStartDate = D.WeekStartDate