2016-08-24 106 views
0

我有一个查询,它使用数据透视表每小时计数。 如何能够每30分钟计数一次?如何计算每半小时?

例如8:00-8:29,8:30-8:59.9:00-9:29等等,直到5:00

SELECT CONVERT(varchar(8),start_date,1) AS 'Day', 

     SUM(CASE WHEN DATEPART(hour,start_date) = 8 THEN 1 ELSE 0 END) as eight , 

     SUM(CASE WHEN DATEPART(hour,start_date) = 9 THEN 1 ELSE 0 END) AS nine, 
     SUM(CASE WHEN DATEPART(hour,start_date) = 10 THEN 1 ELSE 0 END) AS ten, 
     SUM(CASE WHEN DATEPART(hour,start_date) = 11 THEN 1 ELSE 0 END) AS eleven, 
     SUM(CASE WHEN DATEPART(hour,start_date) = 12 THEN 1 ELSE 0 END) AS twelve, 
     SUM(CASE WHEN DATEPART(hour,start_date) = 13 THEN 1 ELSE 0 END) AS one_clock, 
     SUM(CASE WHEN DATEPART(hour,start_date) = 14 THEN 1 ELSE 0 END) AS two_clock, 
     SUM(CASE WHEN DATEPART(hour,start_date) = 15 THEN 1 ELSE 0 END) AS three_clock, 
     SUM(CASE WHEN DATEPART(hour,start_date) = 16 THEN 1 ELSE 0 END) AS four_clock 

FROM test 
where user_id is not null 
GROUP BY CONVERT(varchar(8),start_date,1) 
ORDER BY CONVERT(varchar(8),start_date,1) 

我使用SQL Server 2012(版本的Microsoft SQL Server Management Studio中11.0.3128.0),如下使用iif

回答

1

尝试:

SELECT CONVERT(varchar(8),start_date,1) AS 'Day', SUM(iif(DATEPART(hour,start_date) = 8 and 
DATEPART(minute,start_date) >= 0 and 
DATEPART(minute,start_date) =< 29,1,0)) as eight_tirty 
    FROM test where user_id is not null GROUP BY 
CONVERT(varchar(8),start_date,1) ORDER BY 
CONVERT(varchar(8),start_date,1) 
+0

iff使用不正确 –

1

要获得通过一天半小时计数,这样的事情应该工作。

SELECT day, half_hour, count(1) AS half_hour_count 
FROM (
    SELECT 
     CAST(start_date AS date) AS day, 
     DATEPART(hh, start_date) 
      + 0.5*(DATEPART(n,start_date)/30) AS half_hour 
    FROM test 
    WHERE user_id IS NOT NULL 
) qry 
GROUP BY day, half_hour 
ORDER BY day, half_hour; 

格式化结果可稍后完成。

1

你需要一些东西,然后这个查询就在一起。首先,假设你需要多个日期,你会想要知道什么是Calendar Table(可能是最有用的分析表)。

接下来,你会想要一个现有Numbers表,如果你有一个,或者只是动态生成第一:

WITH Halfs AS (SELECT CAST(0 AS INT) m 
       UNION ALL 
       SELECT m + 1 
       FROM Halfs 
       WHERE m < 24 * 2) 
SELECT m 
FROM Halfs 

(递归CTE - 生成与数字列表的表从0开始)。

这两个表将为您提供基于主表中的时间戳的范围查询的基础。这将使优化程序非常容易地为您所做的任何聚合存储行。这是由CROSS JOIN做了荷兰国际集团的两个表一起在一个子查询,以及添加其他几个派生列的:

WITH Halfs AS (SELECT CAST(0 AS INT) m 
       UNION ALL 
       SELECT m + 1 
       FROM Halfs 
       WHERE m < 24 * 2) 

SELECT calendarDate, m, rangeStart, rangeEnd 
FROM (SELECT Calendar.calendarDate, Halfs.m rangeGroup, 
      DATEADD(minutes, m * 30, CAST(Calendar.calendarDate AS DATETIME2) rangeStart, 
      DATEADD(minutes, (m + 1) * 30, CAST(Calendar.calendarDate AS DATETIME2) rangeEnd     
     FROM Calendar 
     CROSS JOIN Halfs 
     WHERE Calendar.calendarDate >= CAST('20160823' AS DATE) 
      AND Calendar.calendarDate < CAST('20160830' AS DATE) 
      -- OR whatever your date range actually is. 
    ) Range 
ORDER BY rangeStart 

(注意,如果日期的范围足够大,它可能是有益的保存这对于小表和数据集来说,性能增益不太可能是显而易见的)

既然我们有我们的范围,那么获取我们的组,并旋转表是微不足道的。
呵呵,SQL Server有一个特定的运算符PIVOTing

WITH Halfs AS (SELECT CAST(0 AS INT) m 
       UNION ALL 
       SELECT m + 1 
       FROM Halfs 
       WHERE m < 3 * 2) 
       -- Intentionally limiting range for example only 

SELECT calendarDate AS day, [0], [1], [2], [3], [4], [5], [6] 
          -- If you're displaying "nice" names, 
          -- do it at this point, or in the reporting application 
FROM (SELECT Range.calendarDate, Range.rangeGroup 
     FROM (SELECT Calendar.calendarDate, Halfs.m rangeGroup, 
        DATEADD(minutes, m * 30, CAST(Calendar.calendarDate AS DATETIME2) rangeStart, 
        DATEADD(minutes, (m + 1) * 30, CAST(Calendar.calendarDate AS DATETIME2) rangeEnd     
        FROM Calendar 
        CROSS JOIN Halfs 
        WHERE Calendar.calendarDate >= CAST('20160823' AS DATE) 
         AND Calendar.calendarDate < CAST('20160830' AS DATE) 
         -- OR whatever your date range actually is. 
        ) Range 
     LEFT JOIN Test 
      ON Test.user_id IS NOT NULL 
       AND Test.start_date >= Range.rangeStart 
       AND Test.start_date < Range.rangeEnd 
    ) AS DataTable 
PIVOT (COUNT(*) 
     FOR Range.rangeGroup IN ([0], [1], [2], [3], [4], [5], [6])) AS PT 
           -- Only covers the first 6 groups, 
           -- or the first three hours. 
ORDER BY day 

枢轴应照顾个人获得的字段,并且COUNT会自动解决空行。应该是你需要的一切。