我不得不重写一个在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
答案 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_time
是DATE
列(或保证始终在午夜) ,你正在使用的方法是不安全的。更好地说:
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];
这一切都是完全未经测试的,因为你的架构尝试创建一个完整的系统重现有点麻烦,但希望这能让你有一个大致的想法来工作......