在sql中查找去年同一周的计数

Posted

技术标签:

【中文标题】在sql中查找去年同一周的计数【英文标题】:Find the count for last year same week in sql 【发布时间】:2017-09-22 06:27:21 【问题描述】:

我正在使用以下查询根据过去 5-6 周的日期从表中查找计数,如下所示

BEGIN
    SET datefirst 1;
    DECLARE @BeginDate datetime= '2016-10-10' 
    SELECT 
        count(*) as Total
      , datepart(wk, DateCreated) as WeekNumber
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104) as WeekStartDate
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104) as WeekEndDate
    FROM TABLESES
    WHERE   
        CONVERT(date,DateCreated) >= DATEADD(DAY, -42, @BeginDate) 
        AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, @BeginDate)
    GROUP BY      datepart(wk, DateCreated)
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104)
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104)
    ORDER BY datepart(wk, DateCreated)
END

这将返回如下结果集:

    Total   WeekNumber  WeekStartDate   WeekEndDate
    51295   36          29.08.2016      04.09.2016
    48133   37          05.09.2016      11.09.2016
    38991   38          12.09.2016      18.09.2016
    38074   39          19.09.2016      25.09.2016
    37192   40          26.09.2016      02.10.2016
    20835   41          03.10.2016      09.10.2016
    23781   42          10.10.2016      16.10.2016            

现在我想在最后添加一列,其中包含去年同一周数的计数。

我可以在这个查询中实现同样的效果吗?或者我应该为它写一个完全不同的查询?以及如何进行此查询?

【问题讨论】:

你不能只算上一年并加入 weeknumber 吗?因此,创建 2 个 CTE,一个包含 2016 年的数据,一个包含 2015 年的数据,然后在 weeknumber 中加入这些,然后您可以在同一行获得两年的总数。 最困难的部分是找出与同一周数相对应的上一年日期的确切范围。 2016 年 10 月 10 日是星期一 - 一周的第一天。 2015 年 10 月 10 日是星期六,所以简单的 DATEADD(year, -1, ...) 是不够的。我强烈建议使用日历表。 @VladimirBaranov 日期可以忽略。我的情况仅与周数相关 【参考方案1】:

您可以使用UNIONDATEDIFF 来获得上一年的相同内容:

SELECT 
        count(*) as Total
      , datepart(wk, DateCreated) as WeekNumber
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104) as WeekStartDate
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104) as WeekEndDate
    FROM TABLESES
    WHERE   
        CONVERT(date,DateCreated) >= DATEADD(DAY, -42, @BeginDate) 
        AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, @BeginDate)
    GROUP BY      datepart(wk, DateCreated)
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104)
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104)
UNION ALL
SELECT 
        count(*) as Total
      , datepart(wk, DATEDIFF(year,1,DateCreated )) as WeekNumber
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DATEDIFF(year,1,DateCreated ))/7,0),104) as WeekStartDate
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DATEDIFF(year,1,DateCreated ))/7,6),104) as WeekEndDate
    FROM TABLESES
    WHERE   
        CONVERT(date,DateCreated) >= DATEADD(DAY, -42, @BeginDate) 
        AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, @BeginDate)
    GROUP BY      datepart(wk, DATEDIFF(year,1,DateCreated ))
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DATEDIFF(year,1,DateCreated ))/7,0),104)
      , convert(VARCHAR(20),dateadd(week,datediff(day,0,DATEDIFF(year,1,DateCreated ))/7,6),104)
    ORDER BY datepart(wk, DATEDIFF(year,1,DateCreated ))

【讨论】:

【参考方案2】:

把你的最终结果放到一个临时表中,然后做这样的事情:

请务必检查您与上一年的日期逻辑。但希望你明白这个逻辑。我没有测试你的“版本”是否如我所写的那样正确,但我希望你能得到图片。

测试版结果

测试版:

DECLARE @Weeks1 TABLE(
Total int,
Weeknumber INT,
WeekStartDate nvarchar(50),
WeekEndDate nvarchar(50)
)

DECLARE @Weeks2 TABLE(
Total int,
Weeknumber INT,
WeekStartDate nvarchar(50),
WeekEndDate nvarchar(50) 
)


insert into @Weeks1 (Total,Weeknumber,WeekStartDate,Weekenddate)

values  ('51295', '36'        ,'29.08.2016'     ,'04.09.2016'),
    ('48133', '37'        ,'05.09.2016'     ,'11.09.2016'),
    ('38991', '38'        ,'12.09.2016'     ,'18.09.2016'),
    ('38074', '39'        ,'19.09.2016'     ,'25.09.2016'),
    ('37192', '40'        ,'26.09.2016'     ,'02.10.2016'),
    ('20835', '41'        ,'03.10.2016'     ,'09.10.2016'),
    ('23781', '42'        ,'10.10.2016'     ,'16.10.2016')


   insert into @Weeks2 (Total,Weeknumber,WeekStartDate,Weekenddate)

  values  ('324234', '36'       ,'29.08.2015'     ,'04.09.2015'),
    ('22333', '37'        ,'05.09.2015'     ,'11.09.2015'),
    ('23444', '38'        ,'12.09.2015'     ,'18.09.2015'),
    ('566666', '39'       ,'19.09.2015'     ,'25.09.2015'),
    ('4345', '40'         ,'26.09.2015'     ,'02.10.2015'),
    ('8657', '41'         ,'03.10.2015'     ,'09.10.2015'),
    ('8567567', '42'      ,'10.10.2015'     ,'16.10.2015')


Select a.Total,b.Total as 
LastYearTotal,a.Weeknumber,A.WeekStartDate,a.Weekenddate from @Weeks1 a 
inner join @Weeks2 b on a.Weeknumber = b.Weeknumber

使用您的版本:

DECLARE @Weeks1 TABLE(
Total int,
Weeknumber INT,
WeekStartDate nvarchar(50),
WeekEndDate nvarchar(50)
)

DECLARE @Weeks2 TABLE(
Total int,
Weeknumber INT,
WeekStartDate nvarchar(50),
WeekEndDate nvarchar(50)
)


BEGIN
SET datefirst 1;
DECLARE @BeginDate datetime= '2016-10-10' 

insert into @Weeks1 (Total,Weeknumber,WeekStartDate,Weekenddate)

SELECT 
    count(*) as Total
  , datepart(wk, DateCreated) as WeekNumber
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104) as WeekStartDate
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104) as WeekEndDate
FROM TABLESES
WHERE   
    CONVERT(date,DateCreated) >= DATEADD(DAY, -42, @BeginDate) 
    AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, @BeginDate)
GROUP BY      datepart(wk, DateCreated)
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104)
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104)
ORDER BY datepart(wk, DateCreated)
END



BEGIN
SET datefirst 1;
DECLARE @BeginDate2 datetime= '2015-10-10' 

insert into @Weeks2 (Total,Weeknumber,WeekStartDate,Weekenddate)

SELECT 
    count(*) as Total
  , datepart(wk, DateCreated) as WeekNumber
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104) as WeekStartDate
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104) as WeekEndDate
FROM TABLESES
WHERE   
    CONVERT(date,DateCreated) >= DATEADD(DAY, -42, @BeginDate2) 
    AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, @BeginDate2)
GROUP BY      datepart(wk, DateCreated)
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104)
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104)
ORDER BY datepart(wk, DateCreated)
END


Select a.Total,b.Total as 
LastYearTotal,a.Weeknumber,A.WeekStartDate,a.Weekenddate from @Weeks1 a 
inner join @Weeks2 b on a.Weeknumber = b.Weeknumber

【讨论】:

刚刚将第二个 begindate 变量更改为 begindate2 因为你不能有 2 个同名的变量。否则我认为它会起作用。 从字符串转换日期和/或时间时转换失败。我收到的信息是什么 也许是因为我们不使用相同的日期。将日期更正为您通常的书写方式。并确保表上的数据类型正确。或者将日期列设置为 nvarchar 而不是数据类型 DATE 我可以想象您的 WeekStartDate 和 WeekEndDate 是 nvarchar 或 varchar,因为您有 29.08.2016 - 我认为它不适用于数据类型日期。所以尝试根据列来制作表格字符串。 我将类型改为nvarchar,结果是String,否则二进制数据会被截断。【参考方案3】:

如果只有几周很重要,您可以先进行一些日期计算并进行更简单的查询

SET datefirst 1;

 DECLARE @BeginDate datetime = '2016-10-10'; -- must be start of the week , <= last week -6
 declare @nweeks int = 6;
 -- this year interval
 declare @b1Date datetime = dateadd(week, -@nweeks , @BeginDate); --inclusive
 declare @e1Date datetime = dateadd(week, 1 , @BeginDate); -- exclusive
 declare @thisYear int = datepart(year, @b1Date);
 -- previous year interval
 declare @bwk int = datepart(week, @b1Date);
 declare @year2 datetime= dateadd(year,datediff(year,0,@b1Date)-1,0);
 declare @b2Date datetime = dateadd(week, @bwk-1, @year2);
 declare @e2Date datetime = dateadd(week, @bwk + @nweeks, @year2);
 -- check it
 select @BeginDate, @b1Date, @e1Date, @bwk,  @b2Date, @e2Date, datepart(week, @b2Date);

SELECT 
    count(case datepart(year, DateCreated) when @thisYear then 1 end) as TotalThisYear
  , datepart(wk, DateCreated) as WeekNumber
  , convert(VARCHAR(20),dateadd(week,datepart(week,DateCreated)-@bwk -1,@b1Date),104) as WeekStartDate
  , convert(VARCHAR(20),dateadd(day,7*(datepart(week,DateCreated)-@bwk-1)+6,@b1Date),104) as WeekEndDate
  , count(case datepart(year, DateCreated) when @thisYear-1 then 1 end) as TotalPrev
FROM TABLESES
WHERE   
    CONVERT(date,DateCreated) >= @b1Date AND CONVERT(date,DateCreated) <@e1Date
    OR
    CONVERT(date,DateCreated) >= @b2Date AND CONVERT(date,DateCreated) <@e2Date    
GROUP BY datepart(wk, DateCreated)
ORDER BY datepart(wk, DateCreated)

【讨论】:

【参考方案4】:

是的,您可以使用相同的查询,但只需进行少量修改。我使用了 2 个 CTE,一个用于您的查询,另一个用于前一年的几周。然后在 weeknumber 上加入两者以获取所需的最后一列,如下所示。

BEGIN  
SET datefirst 1;  
DECLARE @BeginDate datetime= '2016-10-10'  

;WITH CTE1 as
  SELECT 
    count(*) as Total  
  , datepart(wk, DateCreated) as WeekNumber  
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104) as WeekStartDate  
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104) as WeekEndDate  
FROM TABLESES  
WHERE     
    CONVERT(date,DateCreated) >= DATEADD(DAY, -42, @BeginDate)   
    AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, @BeginDate)  
GROUP BY      datepart(wk, DateCreated)  
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104)  
  , convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104)    

,CTE2 as  
SELECT count(*) as Total    
    ,datepart(wk, dateadd(year, -1, DateCreated)) as WeekNumber  
 FROM TABLESES    
GROUP BY datepart(wk, dateadd(year, -1, DateCreated))  

SELECT CTE1.*, CTE2.Total  
FROM CTE1 JOIN CTE2  
ON CTE1.WeekNumber  = CTE2.WeekNumber  

  END

【讨论】:

以上是关于在sql中查找去年同一周的计数的主要内容,如果未能解决你的问题,请参考以下文章

excel如何自动统计一周的列计数总和?

SQL查找不同值计数,2次重复值计数,3次重复值计数等

同一个 SQL 语句中的多个条件计数 [重复]

查找计数差异 - Microsoft Access 和 SQL

SQL聚合中同一列内的多个值的不同计数

同一查询中的火花计数和过滤计数