根据接收和固定的日期计算每个周末未固定索赔的数量

Caculate the number of not fixed claims at the end of each week based on the dates of reception and fixing

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

create table claims(id int identity(1,1), Reception_Date datetime, Fixing_Date datetime)

如果Fixing_Date为Null,则表示声明未修复,否则已修复。

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

  1. 周数

  2. 该周(星期日)的结束日期

  3. 收到的索赔数量

  4. 固定索赔数

  5. 该周末的非固定索赔数量

数据示例:

    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)

我创建的程序如下,如果你有更好的解决方案欢迎补充

Link to SQL FIDDLE

create proc USP_Received_Fixed_NotFixed(@Y as int=2020)
--Kamel Gazzah 29/11/2020
--Stored procedure to get received, fixed and not fixed claims at the end of each week
--Using Claims Tables (create table claims(id int identity(1,1), Reception_Date datetime, Fixing_Date datetime))
as begin
with 
CteRecep as 
(select year(reception_date) Y,datepart(week,reception_date) W,count(1) N from claims  
where year(reception_date)=@y  
group by year(reception_date) ,datepart(week,reception_date)), 
 
CteFixed as
(select year(fixing_date) Y,datepart(week,fixing_date) W,count(1) N from CLAIMS  
where year(fixing_date)=@y  
group by year(fixing_date) ,datepart(week,fixing_date)),  
 
CteDates as 
(select cast(cast('01/01/'+cast(@y as varchar(4)) as varchar(20)) as date) d  
union all select dateadd(day,1,d) from CteDates where dateadd(day,1,d) <= cast(cast('12/31/'+cast(@y as varchar(4)) as varchar(20)) as date)),  

CteWeeks as 
(select d , datepart(WEEK,d) W,year(d) Y from CteDates where datepart(weekday,d)=7 ), 
 
CteNotFixed as(  
select d [Date],count(1) N from CteWeeks inner join CLAIMS on  
(reception_date <= CteWeeks.d) and (reception_date is not null)  
and((fixing_date is NULL )or (fixing_date > CteWeeks.d))  
group by d) ,


ctereport as(
 
select  
CteWeeks.d DATE,year(CteWeeks.d) Y,datepart(week,CteWeeks.d)W,isnull(CteRecep.N,0)[RECEIVED],isnull(CteFixed.N,0)[FIXED],isnull(CteNotFixed.N,0) [NotFIXED] from CteWeeks
left outer join CteRecep on CteWeeks.w=CteRecep.w and CteRecep.y=CteWeeks.y  
left outer join CteFixed on CteWeeks.y=CteFixed.y and CteWeeks.w=CteFixed.w  
left outer join CteNotFixed on CteWeeks.y=year(CteNotFixed.date) and CteWeeks.w=datepart(week,CteNotFixed.date))


select Date,W ,Received,Fixed,NotFixed from ctereport
 
OPTION (MAXRECURSION 0) 
end 

不要在每次执行时重新计算周 table,而是建立一个永久日期 table 并重复使用它。在我这边,您的查询平均需要 140 毫秒,而永久日期 table 需要 6 毫秒

也不要太依赖隐式转换,DATE 到 DATETIME 将被隐式转换并减慢您的查询。它还可能使您的查询 non-SARGABLE 忽略索引并导致 table 扫描。

这是一个基本的日期 table 填充脚本,对于本次演示,我将其保留为临时 table,最好将其创建为实际的索引 table

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

一旦你有了日期table你就可以开始利用它了,这个查询平均运行 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