编写一个查询,显示同一行上不同条件的记录计数

时间:2013-07-26 17:03:06

标签: sql sql-server sql-server-2005

我有一个类似于下面的查询,显示了几个表的记录计数。

SELECT 'SomeTable' as tname, COUNT(*) as ttlRecords FROM SomeTable WHERE SubjectID = @SubjectID
UNION
SELECT 'AnotherTable' as tname, COUNT(*) as ttlRecords FROM AnotherTable WHERE SubjectID = @SubjectID
UNION
SELECT 'YetAnotherTable' as tname, COUNT(*) as ttlRecords FROM YetAnotherTable WHERE SubjectVersionID = @SubjectVersionID

结果看起来像这样......

tname            ttlRecords
SomeTable        25
AnotherTable     55
YetAnotherTable  120

现在,我想修改它以进一步显示具有特定条件的一些计数。对于此示例,我有一个RegionID,指定记录是与加拿大或美国地区相关联。所以我想在ttlRecordCount的同一行显示USRecordCount和CARecordCount,如下所示......

tname            ttlRecords   USRecordCount   CARecordCount
SomeTable        25           10              15
AnotherTable     55           52              3
YetAnotherTable  120          100             20

我知道我可以使用子查询来执行此操作,如下所示,但它似乎很草率且可能很慢。

SELECT 
  'SomeTable' as tname, 
  (SELECT COUNT(*) FROM SomeTable WHERE SubjectID = @SubjectID) as ttlRecords,
  (SELECT COUNT(*) FROM SomeTable WHERE SubjectID = @SubjectID AND RegionTypeID = 1) as USRecordCount,
  (SELECT COUNT(*) FROM SomeTable WHERE SubjectID = @SubjectID AND RegionTypeID = 2) as CARecordCount
UNION
SELECT 
  'AnotherTable' as tname, 
  (SELECT COUNT(*) FROM AnotherTable WHERE SubjectID = @SubjectID) as ttlRecords,
  (SELECT COUNT(*) FROM AnotherTable WHERE SubjectID = @SubjectID AND RegionTypeID = 1) as USRecordCount,
  (SELECT COUNT(*) FROM AnotherTable WHERE SubjectID = @SubjectID AND RegionTypeID = 2) as CARecordCount
UNION
SELECT 
  'YetAnotherTable' as tname, 
  (SELECT COUNT(*) FROM YetAnotherTable WHERE SubjectVersionID = @SubjectVersionID) as ttlRecords,
  (SELECT COUNT(*) FROM YetAnotherTable WHERE SubjectVersionID = @SubjectVersionID AND RegionTypeID = 1) as USRecordCount,
  (SELECT COUNT(*) FROM YetAnotherTable WHERE SubjectVersionID = @SubjectVersionID AND RegionTypeID = 2)as CARecordCount

我的问题是,有更好的方式来写这个吗?

2 个答案:

答案 0 :(得分:2)

您可以在SUM()语句

中使用case语句
SUM(CASE WHEN A = B THEN 1 ELSE 0 END) as WhenAEqualsB

更新了原始信息:

SELECT 
  'SomeTable' as tname, 
  COUNT(1) as ttlRecords,
  SUM(CASE WHEN RegionTypeID = 1 THEN 1 ELSE 0 END) as USRecordCount,
  SUM(CASE WHEN RegionTypeID = 2 THEN 1 ELSE 0 END) as CARecordCount
From
    SomeTable
where
    SubjectID = @SubjectID
UNION
SELECT 
  'AnotherTable' as tname, 
  COUNT(1) as ttlRecords,
  SUM(CASE WHEN RegionTypeID = 1 THEN 1 ELSE 0 END) as USRecordCount,
  SUM(CASE WHEN RegionTypeID = 2 THEN 1 ELSE 0 END) as CARecordCount
FROM
    AnotherTable
where
    SubjectID = @SubjectID
UNION
SELECT 
  'YetAnotherTable' as tname, 
  COUNT(1) as ttlRecords,
  SUM(CASE WHEN RegionTypeID = 1 THEN 1 ELSE 0 END) as USRecordCount,
  SUM(CASE WHEN RegionTypeID = 2 THEN 1 ELSE 0 END) as CARecordCount
FROM
    YetAnotherTable
where
    SubjectID = @SubjectID

答案 1 :(得分:2)

是的,可以使用模式

SELECT
    SUM(CASE WHEN <condition_1> THEN 1 ELSE 0 END) AS NumCond1,
    SUM(CASE WHEN <condition_2> THEN 1 ELSE 0 END) AS NumCond2,
    ....
    SUM(CASE WHEN <condition_N> THEN 1 ELSE 0 END) AS NumCondN
FROM <table_name>

这将需要对表中的所有记录进行一次迭代。每个记录将由每个聚合表达式(SUM s)进行评估,并且只有在记录与相应条件匹配时才会增加计数。

请注意,这可能不会更快;它可能会慢得多!考虑这样一种情况,即表包含10亿条记录,但每条条件只有1条记录匹配,并且条件中使用的每个列组合都有索引。在这种情况下,使用索引直接找到那些少量记录比读取所有10亿行以找到它们要快得多。也就是说,使用问题中描述的seaprate子查询方法。这仅适用于您不需要计算总行数的情况,如下例所示。

以下是使用其他优化进行转换的完整示例,该示例可能适用于您的实际工作,将任何常见条件移至WHERE子句中。请注意使用COUNT(*)同时获取总行数。

SELECT
    'SomeTable' as tname,
    COUNT(*) as ttlRecords,
    SUM(CASE WHEN RegionTypeID = 1 THEN 1 ELSE 0 END) as USRecordCount,
    SUM(CASE WHEN RegionTypeID = 2 THEN 1 ELSE 0 END) as CARecordCount
FROM SomeTable
WHERE SubjectID = @SubjectID
UNION ALL
SELECT
    'AnotherTable' as tname,
    COUNT(*) as ttlRecords,
    SUM(CASE WHEN RegionTypeID = 1 THEN 1 ELSE 0 END) as USRecordCount,
    SUM(CASE WHEN RegionTypeID = 2 THEN 1 ELSE 0 END) as CARecordCount
FROM AnotherTable
WHERE SubjectID = @SubjectID
UNION ALL
SELECT
    'YetAnotherTable' as tname,
    COUNT(*) as ttlRecords,
    SUM(CASE WHEN RegionTypeID = 1 THEN 1 ELSE 0 END) as USRecordCount,
    SUM(CASE WHEN RegionTypeID = 2 THEN 1 ELSE 0 END) as CARecordCount
FROM YetAnotherTable
WHERE SubjectVersionID = @SubjectVersionID