用于汇总最近7天数据的SQL查询

时间:2016-05-27 12:11:32

标签: sql sql-server

我们假设我有一个这样的表结构。

CheckIn
- int checkInId pk
- int companyPositionId
- Date checkInDate

假设我想要计算从给定日期开始的最后7天的所有检查。最好的方法是什么?现在我正在查询7个日期和公司位置中的每一个。目前这太慢了,因为可能有很多公司位置* 7天。如何将其汇总到一个查询中?

最简单的生成过去7天的日期并构建一个长查询?那我可以按7天的每一天的日期范围分组计数吗?

理想的结果可能如下:

companyPositionId, date1Count, date2Count, date3Count, date4Count, date5Count, date6Count.

示例数据:

checkInId | companyPositionId | checkInDate
1         | 1                 | 1970-01-01
2         | 1                 | 1970-01-02
3         | 1                 | 1970-01-03
4         | 1                 | 1970-01-04
5         | 1                 | 1970-01-05
6         | 1                 | 1970-01-06
7         | 1                 | 1970-01-07
8         | 2                 | 1970-01-01
9         | 2                 | 1970-01-02
10        | 2                 | 1970-01-03
11        | 2                 | 1970-01-04
12        | 2                 | 1970-01-05
13        | 2                 | 1970-01-06
14        | 2                 | 1970-01-07*
15        | 2                 | 1970-01-07*

我目前的疑问是:

SELECT * FROM CheckIn
  WHERE (startDate) <= (inputDate) 
    AND (inputDate) <= (endDate)
    AND companyPositionId = (companyPositionId);

然后循环遍历从当天开始到当天结束生成的每个startDate / endDate。然后是每个companyPositionId。

理想的结果:

companyPositionId | date1Count | date2Count | date3Count | date4Count | date5Count | date6Count | date7Count
1                 | 1          | 1          | 1          | 1          | 1          | 1          | 1
2                 | 1          | 1          | 1          | 1          | 1          | 1          | 2

4 个答案:

答案 0 :(得分:1)

您可以使用PIVOT命令或条件SUM执行此操作:

DECLARE @my_date DATE = CAST(GETDATE() AS DATE)

SELECT
    companyPositionId,
    SUM(CASE WHEN CAST(checkInDate AS DATE) = DATEADD(DAY, -7, @my_date) THEN 1 ELSE 0 END) AS date1Count,
    SUM(CASE WHEN CAST(checkInDate AS DATE) = DATEADD(DAY, -6, @my_date) THEN 1 ELSE 0 END) AS date2Count,
    SUM(CASE WHEN CAST(checkInDate AS DATE) = DATEADD(DAY, -5, @my_date) THEN 1 ELSE 0 END) AS date3Count,
    SUM(CASE WHEN CAST(checkInDate AS DATE) = DATEADD(DAY, -4, @my_date) THEN 1 ELSE 0 END) AS date4Count,
    SUM(CASE WHEN CAST(checkInDate AS DATE) = DATEADD(DAY, -3, @my_date) THEN 1 ELSE 0 END) AS date5Count,
    SUM(CASE WHEN CAST(checkInDate AS DATE) = DATEADD(DAY, -2, @my_date) THEN 1 ELSE 0 END) AS date6Count,
    SUM(CASE WHEN CAST(checkInDate AS DATE) = DATEADD(DAY, -1, @my_date) THEN 1 ELSE 0 END) AS date7Count
FROM
    CheckIn
WHERE
    checkInDate BETWEEN DATEADD(DAY, -7, GETDATE()) AND DATEADD(DAY, -1, GETDATE())
GROUP BY
    companyPositionId

如果您的checkInDate有时间组件,那么您需要考虑到这一点。

我声明@my_date变量只是为了避免在查询中多次重复该表达式,但是你可以用该表达式替换变量,它也可以工作。您也可以使用可能具有更好性能的BETWEEN,因为优化器可能会使用checkInDate上的索引。只计算每一天的午夜/ 11:59:59,而不是寻找平等。

答案 1 :(得分:0)

看看

Declare @d date= '2016-05-05';  -- parameter, we need this day and six previous

Select
  companyPositionId
  ,date1Count = count(case checkInDate when @d then checkInId end) 
  ,date2Count = count(case checkInDate when dateadd(d,-1,@d) then checkInId end)
  --...
from checkIn
where checkInDate between dateadd(d,-6,@d) and @d
group by companyPositionId
order by companyPositionId;

答案 2 :(得分:0)

创建数据:

CREATE TABLE #checkin (

 checkInId INT IDENTITY(1, 1), 
 companyPositionId int, 
 checkInDate DATE
)

DECLARE @counter INT = 100
WHILE @counter > 0
BEGIN

INSERT INTO #checkin
        ( companyPositionId, checkInDate )
VALUES  ( RAND() * 10 + 1, -- 10 possible companies? 
          DATEADD(day, RAND()*-7, GETDATE())  -- random days in the last 2 weeks
          )

SET @counter = @counter - 1
END

逻辑从这里开始:

DECLARE 
    @now DATETIME   = GETDATE(),
    @days INT       = -7 -- Our interval of interest

这个逻辑部分借鉴了Bogdan Sahlean,他的结果得到了所有的&#39; 1&#39;对我来说,所以我更改了dayNum计算

SELECT *
FROM (
    SELECT  companyPositionId, checkInId, 1 + CAST(DATEDIFF(DAY,checkInDate, @now) AS INT) AS DayNum
    FROM    #CheckIn
    WHERE   checkInDate BETWEEN CAST(DATEADD(DAY, @days, @now) AS DATE) AND @now  
) AS ps -- Pivot source
PIVOT ( COUNT(checkInId) FOR DayNum IN ([1], [2], [3], [4], [5], [6], [7]) ) AS p


DROP TABLE #checkin

答案 3 :(得分:0)

这是一个快速透视示例,假设您正在寻找@inputDate的前7天。这应该与时间组件一起工作,因为它仅在几天内从DATEDIFF开始。

DECLARE @InputDate DATE = '1/8/1970'
;WITH CTE AS (
    SELECT *, DATEDIFF(DD, checkInDate, @InputDate) AS DaysAgo FROM @CheckIns
)
    SELECT
        companyPositionId,
        SUM([7]) AS date1Count,
        SUM([6]) AS date2Count,
        SUM([5]) AS date3Count,
        SUM([4]) AS date4Count,
        SUM([3]) AS date5Count,
        SUM([2]) AS date6Count,
        SUM([1]) AS date7Count -- Reversed columns since you wanted 7 to be most recent day 
    FROM CTE
        PIVOT (COUNT(checkInId) FOR DaysAgo IN ([1], [2], [3], [4], [5], [6], [7])) PVT
    GROUP BY
        companyPositionId

这样可以得到符合您所需输出的以下结果:

companyPositionId date1Count  date2Count  date3Count  date4Count  date5Count  date6Count  date7Count
----------------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
1                 1           1           1           1           1           1           1
2                 1           1           1           1           1           1           2