我们假设我有一个这样的表结构。
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
答案 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