SQL Server 2005版本开始支持了窗口函数(Windowing Function)和OVER字句。SQL Server 2012版本开始支持了窗口函数的ORDER BY字句实现连续/累计聚合功能。但是有个功能到SQL Server 2014版本为止(从目前SQL Server 2016 CTP3来看,还是不支持),就是COUNT(DISTINCT XXX) OVER(PARTITION BY YYY ORDER BY ZZZ)。
一直觉得这个事情没有办法用比较巧妙地办法做到,只能是用CROSS APPLY或者循环去把数据集“UNION ALL”起来。今天在Google上找到了一个别人想到的办法,顿时觉得自己怎么那么笨,没有想到这个办法呢。巧妙之处在于用一个带有DENSE_RANK函数的子查询配合MAX函数实现。下面是测试代码:
CREATE TABLE Foo ( fookey INT PRIMARY KEY, company VARCHAR(30), sales_rep VARCHAR(30), client VARCHAR(30)); INSERT INTO Foo VALUES(1, ‘ABC Corp.‘, ‘Joe‘, ‘Client1‘); INSERT INTO Foo VALUES(2, ‘ABC Corp.‘, ‘Joe‘, ‘Client2‘); INSERT INTO Foo VALUES(6, ‘ABC Corp.‘, ‘Joe‘, ‘Client2‘); INSERT INTO Foo VALUES(3, ‘ABC Corp.‘, ‘Peter‘, ‘Client2‘); INSERT INTO Foo VALUES(4, ‘DEF Corp.‘, ‘Joe‘, ‘Client1‘); INSERT INTO Foo VALUES(5, ‘DEF Corp.‘, ‘Joe‘, ‘Client3‘); SELECT DISTINCT company, sales_rep, client, MAX(rk1) OVER(PARTITION BY sales_rep) AS rep_distinct_client_cnt, MAX(rk2) OVER(PARTITION BY company) AS company_distinct_client_cnt FROM ( SELECT fookey, company, sales_rep, client, DENSE_RANK() OVER(PARTITION BY sales_rep ORDER BY client) As rk1, DENSE_RANK() OVER(PARTITION BY company ORDER BY client) As rk2 FROM Foo) AS F;
这个办法精妙的地方便是利用了DENSE_RANK本身会对相同值返回相同的排序号的特点,这点恰恰符合了我们需要DISTINCT的作用。其次,排序号和COUNT的相同之处不就是对记录的个数统计吗?那么取得最大的排序号不就相当于拿到了COUNT的值了吗?确实高明。感叹自己过去怎么就没想到呢?还是很开心可以知道这个办法的。
时间: 2024-10-21 05:13:28