计算日期范围和个别日期

时间:2013-03-29 19:28:57

标签: sql-server sql-server-2005 count date-range

我不得不重写一个在ColdFusion中使用SQL查询和查询查询组合完成的项目。有几十个查询引用了原始的SQL Query结果集,但它并没有被抽象为适用于不同的事件。所以我想通过将大部分计数转移到SQL来改进它。我得到了他们需要工作的前6个计数(不确定是否以最佳方式)。但是,除了这些之外,我还需要能够在整个日期范围内进行细分,而且还要在该日期范围内针对唯一计数进行细分。

到目前为止,查询是:

 SELECT Count(CASE
           WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
           ELSE NULL
         END)              AS total_scans,
   Count(CASE
           WHEN type IN ( 2, 8 ) THEN barcode
           ELSE NULL
         END)              AS total_creds,
   Count(barcode)          AS total_scans,
   Count(DISTINCT CASE
                    WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
                    ELSE NULL
                  END)     AS unique_scans,
   Count(DISTINCT CASE
                    WHEN type IN ( 2, 8 ) THEN barcode
                    ELSE NULL
                  END)     AS unique_creds,
   Count(DISTINCT barcode) AS unique_scans 
FROM   (SELECT c.id,
           a.barcode,
           d.type,
           c.location,
           Datepart(mm, a.scan_time)     AS scan_month,
           Datepart(dd, a.scan_time)     AS scan_day,
           Datepart(hour, a.scan_time)   AS scan_hour,
           Datepart(minute, a.scan_time) AS scan_min
    FROM   [scan_11pc_gate_entries] AS a
           INNER JOIN scan_units AS b
                   ON a.scanner = b.id
           INNER JOIN scan_gates AS c
                   ON b.gate = c.id
           INNER JOIN [scan_11pc_gate_allbarcodes] AS d
                   ON a.barcode = d.barcode
    WHERE  ( c.id IN (SELECT id
                      FROM   scan_gates
                      WHERE  ( event_id = 21 )) )
           AND ( a.valid IN ( 1, 8 ) )
           AND a.scan_time >= '20110808'
           AND a.scan_time <= '20110814') data  

1 个答案:

答案 0 :(得分:0)

我在这里看到了很多其他改进/优化的空间,但要满足当前的要求:

 SELECT d, Count(CASE WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
           ELSE NULL END) AS total_scans,
   Count(CASE WHEN type IN ( 2, 8 ) THEN barcode
           ELSE NULL END) AS total_creds,
   Count(barcode)         AS total_scans,
   Count(DISTINCT CASE WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
           ELSE NULL END) AS unique_scans,
   Count(DISTINCT CASE WHEN type IN ( 2, 8 ) THEN barcode
           ELSE NULL END) AS unique_creds,
   Count(DISTINCT barcode) AS unique_scans 
FROM   (SELECT c.id, -- is this column necessary?
           a.barcode,
           d.type,
           c.location, -- is this column necessary?
           d = DATEADD(DAY, DATEDIFF(DAY, 0, a.scan_time), 0)
    FROM   [scan_11pc_gate_entries] AS a
           INNER JOIN scan_units AS b
                   ON a.scanner = b.id
           INNER JOIN scan_gates AS c
                   ON b.gate = c.id
                  AND c.event_id = 21 -- join criteria, 
                     -- shouldn't be an extra IN clause
           INNER JOIN [scan_11pc_gate_allbarcodes] AS d
                   ON a.barcode = d.barcode
    WHERE  ( a.valid IN ( 1, 8 ) )
           AND a.scan_time >= '20110808'
           AND a.scan_time <= '20110814') data  
GROUP BY d
ORDER BY d;

请注意,>=<=BETWEEN相同,除非scan_timeDATE列(或保证始终在午夜) ,你正在使用的方法是不安全的。更好地说:

           AND a.scan_time >= '20110808'
           AND a.scan_time <  '20110815'

更多信息:


修改

了解这是基于我从评论和问题拼凑而成的信息,这些信息远不是您的环境和工作量的完整图片,您可能会觉得有用的索引视图将是:

CREATE VIEW dbo.myview 
WITH SCHEMABINDING
AS
  SELECT c.event_id,
         a.barcode,
         [type] = CASE WHEN d.[type] IN (2,8) THEN 'c' ELSE 's' END,
         scan_date = DATEADD(DAY, DATEDIFF(DAY, 0, a.scan_time), 0),
         total = COUNT_BIG(*)
    FROM dbo.scan_11pc_gate_entries AS a
    INNER JOIN dbo.can_units AS b
            ON a.scanner = b.id
    INNER JOIN dbo.scan_gates AS c
            ON b.gate = c.id
    INNER JOIN dbo.scan_11pc_gate_allbarcodes AS d
            ON a.barcode = d.barcode
    WHERE (a.valid IN (1,8))
      AND d.[type] IN (2,3,4,5,8,9)
    GROUP BY 
      c.event_id,
      a.barcode,
      CASE WHEN d.[type] IN (2,8) THEN 'c' ELSE 's' END,
      DATEADD(DAY, DATEDIFF(DAY, 0, a.scan_time), 0);
GO
CREATE UNIQUE CLUSTERED INDEX x 
  ON dbo.myview(event_id, barcode, [type], scan_date);

现在你可以编写一个类似这样的查询:

SELECT [date] = CONVERT(CHAR(8), scan_date, 112), 
  SUM(CASE WHEN [type] = 's' THEN total ELSE 0 END) AS total_scans,
  SUM(CASE WHEN [type] = 'c' THEN total ELSE 0 END) AS total_creds,
  COUNT(CASE WHEN [type] = 's' THEN 1 END) AS unique_scans,
  COUNT(CASE WHEN [type] = 'c' THEN 1 END) AS unique_creds
FROM dbo.myview WITH (NOEXPAND) -- in case STD Edition
WHERE event_id = 21
  AND scan_date BETWEEN '20110808' AND '20110814'
GROUP BY scan_date
UNION ALL
SELECT [date] = 'weekly', 
  SUM(CASE WHEN [type] = 's' THEN total ELSE 0 END) AS total_scans,
  SUM(CASE WHEN [type] = 'c' THEN total ELSE 0 END) AS total_creds,
  COUNT(DISTINCT CASE WHEN [type] = 's' THEN barcode END) AS unique_scans,
  COUNT(DISTINCT CASE WHEN [type] = 'c' THEN barcode END) AS unique_creds
FROM dbo.myview WITH (NOEXPAND) -- in case STD Edition
WHERE event_id = 21
  AND scan_date BETWEEN '20110808' AND '20110814'
ORDER BY [date];

这一切都是完全未经测试的,因为你的架构尝试创建一个完整的系统重现有点麻烦,但希望这能让你有一个大致的想法来工作......