只计算多个字段的不同值组合。

时间:2013-06-07 13:21:58

标签: sql sql-server tsql sql-server-2005 sql-server-2012

请考虑以下事项:

IF OBJECT_ID ('tempdb..#Customer') IS NOT NULL
   DROP TABLE #Customer;

CREATE TABLE #Customer
(
   CustomerKey    INT IDENTITY (1, 1) NOT NULL
  ,CustomerNum    INT NOT NULL
  ,CustomerName   VARCHAR (25) NOT NULL
  ,Planet         VARCHAR (25) NOT NULL
)
GO

INSERT INTO #Customer (CustomerNum, CustomerName, Planet)
VALUES  (1, 'Anakin Skywalker', 'Tatooine')
      , (2, 'Yoda', 'Coruscant')
      , (3, 'Obi-Wan Kenobi', 'Coruscant')
      , (4, 'Luke Skywalker', 'Tatooine')
      , (4, 'Luke Skywalker', 'Tatooine')
      , (4, 'Luke Skywalker', 'Bespin')
      , (4, 'Luke Skywalker', 'Bespin')
      , (4, 'Luke Skywalker', 'Endor')
      , (4, 'Luke Skywalker', 'Tatooine')
      , (4, 'Luke Skywalker', 'Kashyyyk');

请注意,共有10条记录。我知道我可以获得CustomerName和PLanet的不同组合列表,其中包含以下两个查询之一。

SELECT DISTINCT CustomerName, Planet FROM #Customer;

SELECT CustomerName, Planet FROM #Customer
GROUP BY CustomerName, Planet;

但是,我想要的是一种简单的方法来获取这些值的计数,而不是值本身。我想要一种快速输入的方式,但也有高效的方式。我知道我可以将值加载到CTE,临时表,表变量或子查询中,然后计算记录。有没有更好的方法来实现这一目标?

2 个答案:

答案 0 :(得分:6)

这将在2005年有效:

SELECT COUNT(*) AS cnt
FROM
 ( SELECT 1 AS d
   FROM  Customer
   GROUP BY Customername, Planet
 ) AS t ;

SQL-Fiddle 中进行测试。将使用(CustomerName, Planet)上的索引,请参阅查询计划(2012版):

Query Plan

最简单的思考,“在子查询中获取所有不同的值,然后计算”,yiields采用相同的相同计划:

SELECT COUNT(*) AS cnt
FROM
 ( SELECT DISTINCT Customername, Planet
   FROM  Customer
 ) AS t ;

还有一个(使用@Aaron Bertrand)使用排名函数ROW_NUMBER()(不确定它是否在2005版本中也有效,但你可以测试):

SELECT COUNT(*) AS cnt
FROM 
  (SELECT rn = ROW_NUMBER() 
          OVER (PARTITION BY CustomerName, Planet 
                ORDER BY CustomerName) 
   FROM Customer) AS x 
WHERE rn = 1 ;

还有其他方法可以写这个(即使没有子查询,也就是@Mikael Erksson!),但效率不高。

答案 1 :(得分:2)

子查询/ CTE方法是“正确”的方法。

快速(在打字但不一定是性能方面)和肮脏的方式是:

select count(distinct customername+'###'+Planet)
from #Customer;

'###'用于分隔值,这样就不会发生意外碰撞。