每周和每月SQL的COUNT总计

时间:2016-07-09 06:28:34

标签: sql sql-server database

我有一张表格,我必须按天,按周和按月计算分配给每个用户的总行数。

表BooksIssued

BOOKID    ISSUEDUSER    DATE
 1            A        20160708
 2            A        20160709
 3            A        20160708
 4            A        20150102
 5            B        20160709
 6            C        20160708
 7            C        20160708

现在我必须为每个用户发送COUNT每日,每周和每月的书籍

每日是今天(20160709) 每周是周日至周六 每月是整月

结果应为

ISSUEDUSER    DAILYBOOKS WEEKLYBOOKS  MONTHLYBOOKS
  A               1       3           3
  B               1       1           1
  C               0       2           2

我已经为每日发布的

做了这个SQL
SELECT ISSUEDUSER, COUNT(BOOKID) AS DAILYBOOKS
FROM BOOKSISSUED
WHERE DATE = CONVERT(VARCHAR(11), SYSDATETIME(), 112)
GROUP BY ISSUEDUSER

有人可以帮我写三个组合 SQL吗?

由于

艾登

2 个答案:

答案 0 :(得分:3)

您可能需要添加WHERE子句以仅检索当前月份的记录

SELECT ISSUEDUSER, 
       SUM(CASE WHEN DATE = DATEADD(DAY, DATEDIFF(DAY, 0, SYSDATETIME()), 0))
                THEN 1 ELSE 0 END) AS DAILYBOOKS,
       SUM(CASE WHEN DATE >= DATEADD(WEEK, DATEDIFF(WEEK, 0, SYSDATETIME()), 0)
                AND  DATE <  DATEADD(WEEK, DATEDIFF(WEEK, 0, SYSDATETIME()) + 1, 0)
                THEN 1 ELSE 0 END) AS WEEKLYBOOKS,
       COUNT(*) AS MONTHLYBOOKS
FROM   BOOKSISSUED
WHERE  DATE >= DATEADD(MONTH, DATEDIFF(MONTH, 0, SYSDATETIME()), 0)
AND    DATE <  DATEADD(MONTH, DATEDIFF(MONTH, 0, SYSDATETIME()) + 1, 0)
GROUP BY ISSUEDUSER

编辑:[日期]列为INT

SELECT ISSUEDUSER, 
       SUM(CASE WHEN DATE = CONVERT(INT, CONVERT(VARCHAR(8), SYSDATETIME(), 112))
                THEN 1 ELSE 0 END) AS DAILYBOOKS,
       SUM(CASE WHEN DATE >= CONVERT(INT, CONVERT(VARCHAR(8), DATEADD(WEEK, DATEDIFF(WEEK, 0, SYSDATETIME()), 0), 112))
                AND  DATE <  CONVERT(INT, CONVERT(VARCHAR(8), DATEADD(WEEK, DATEDIFF(WEEK, 0, SYSDATETIME()) + 1, 0), 112))
                THEN 1 ELSE 0 END) AS WEEKLYBOOKS,
       COUNT(*) AS MONTHLYBOOKS
FROM   BOOKSISSUED
WHERE  DATE >= CONVERT(INT, CONVERT(VARCHAR(6), SYSDATETIME(), 112) + '01')
AND    DATE <  CONVERT(INT, CONVERT(VARCHAR(6), DATEADD(MONTH, 1, SYSDATETIME()), 112) + '01')
GROUP BY ISSUEDUSER

答案 1 :(得分:2)

  • 您应该考虑投资合法的Date_Time表。

它使得比较官方开始和结束的周更容易和实用。嘿,你甚至可以使用索引编制!

然而,还有另一种方式。如您所见,DATEPART返回我们正在寻找的ISO月份和周。

所以如果我们的年份是正确的,我们现在知道我们的界限在哪里,并且可以在IIF(<boolean_expression>, <true_expression>, <false_expression>)内轻松使用COUNT(<column>)声明。 COUNT忽略了NULL,因此我们将TRUE设置为1,将FALSE设置为NULL。 :d

-- Note, I changed the column [Date] to [Dates]
DECLARE @Date INT
SET @Date = CAST(CAST(SYSDATETIME() AS VARCHAR(4) ) + '0101' AS INT)

SELECT  ISSUEDUSER--DATEPART(YYYY, CAST(Dates AS VARCHAR(10) ) )
      , COUNT( IIF(DATEDIFF(MM, CAST(Dates AS VARCHAR(10) ), GETDATE() ) = 0
           , 1
           , NULL) ) AS MONTHS
      , COUNT( IIF(DATEDIFF(WW, CAST(Dates AS VARCHAR(10) ), GETDATE() ) = 0
           , 1
           , NULL) ) AS Weeks
      , COUNT( IIF(DATEDIFF(DD, CAST(Dates AS VARCHAR(10) ), GETDATE() ) = 0
           , 1
           , NULL) ) AS Days
FROM    #BookReport
WHERE DATES >= @Date
GROUP BY ISSUEDUSER
--results    
ISSUEDUSER  MONTHS  Weeks   Days
A           3       3       1
B           1       1       1 
C           2       2       0

请注意,您可以通过调整boolean语句来扩展允许的日期差异!无需额外编码。

另请注意,您的示例实际上只有一个日期不是同一个月,周或日(在一天内),尽管在我的示例中我要求Days与查询的日期相同看起来有点不同。

冷静观察:

  • DATE根据定义没有格式,而DATEPART可以从结构良好的Datetime 字符串进行猜测,因此没有理由对您的日期进行双重投射柱。但是,如果您的模式发生变化,则可能需要添加CONVERT
  • DATEPART为您提供标准(ISO)月和周识别,这意味着此处不需要Date_Time表。 :)
  • DATEDIFF在这里很神奇,让您的Boolean语句非常容易使用。
  • 很漂亮,没有?
  • MSDN的DATEPART页面值得一看。