如何在MS SQL中的单个SELECT查询中创建新的“共享”组

时间:2017-02-06 14:48:37

标签: sql-server

我正在尝试按照您通常的方式对SELECT进行分组 - 同时创建一个新的“共享/聚合组”,将其添加到原始结果集中,而不使用辅助SELECT和UNION。

辅助SELECT和UNION是不可能的,因为实际使用它是一些非常大的表,有很多连接,所以它可能会减慢。所以UNION方式绝对是不可能的。

我已尽力用以下简化示例来说明这一点:

BEGIN TRAN

CREATE TABLE #MyTable
(
    id      INT,
    name    VARCHAR(255)
)

INSERT INTO #MyTable VALUES (1,'cola');
INSERT INTO #MyTable VALUES (2,'cola');
INSERT INTO #MyTable VALUES (3,'cola');
INSERT INTO #MyTable VALUES (4,'fanta');
INSERT INTO #MyTable VALUES (5,'fanta');
INSERT INTO #MyTable VALUES (6,'fanta');
INSERT INTO #MyTable VALUES (7,'water');
INSERT INTO #MyTable VALUES (8,'water');
INSERT INTO #MyTable VALUES (9,'water');
INSERT INTO #MyTable VALUES (10,'cola');
INSERT INTO #MyTable VALUES (11,'cola');

SELECT
    CASE 
        WHEN name = 'cola' OR name = 'fanta'
            THEN 'soda'
        ELSE
            name
    END as name,
    COUNT(distinct id) as count
FROM #MyTable
GROUP BY name

ROLLBACK TRAN



Actual output:

soda    5
soda    3
water   3

Desired output:

cola    5
fanta   3
soda    8 <- this is the "shared/aggregate group"
water   3

3 个答案:

答案 0 :(得分:1)

正如Panagiotis Kanavos在上面的评论中正确指出的那样,这可以使用ROLLUP完成:

BEGIN TRAN

CREATE TABLE #BeverageType
(
    name    VARCHAR(255)
)

INSERT INTO #BeverageType VALUES ('Soda');
INSERT INTO #BeverageType VALUES ('Other');

CREATE TABLE #UserBeverage
(
    id      INT,
    name    VARCHAR(255)
)

INSERT INTO #UserBeverage VALUES (1,'cola');
INSERT INTO #UserBeverage VALUES (2,'cola');
INSERT INTO #UserBeverage VALUES (3,'cola');
INSERT INTO #UserBeverage VALUES (1,'fanta'); -- <- NOTE: user 1 drinks both cola and fanta so the as intended the user is only counted 1 time in the ROLLUP 'Soda' group (7)
INSERT INTO #UserBeverage VALUES (5,'fanta');
INSERT INTO #UserBeverage VALUES (6,'fanta');
INSERT INTO #UserBeverage VALUES (7,'water');
INSERT INTO #UserBeverage VALUES (8,'water');
INSERT INTO #UserBeverage VALUES (9,'water');
INSERT INTO #UserBeverage VALUES (10,'cola');
INSERT INTO #UserBeverage VALUES (11,'cola');

SELECT ub.name, bt.name AS groupName, COUNT(distinct id) as uniqueUserCount
FROM #UserBeverage as ub
JOIN #BeverageType as bt
ON CASE
    WHEN (ub.name = 'water')
        THEN 'Other'
    ELSE
        'Soda'
    END = bt.name
GROUP BY ROLLUP(bt.name, ub.name)

ROLLBACK TRAN

输出:

cola    Soda    5
fanta   Soda    3
water   Other   3
NULL    Other   3
NULL    Soda    7
NULL    NULL    10

答案 1 :(得分:0)

你应该在任何地方重复CASE声明。

SELECT
    CASE WHEN name = 'cola' OR name = 'fanta'
                    THEN 'soda' ELSE name END as name,
    COUNT((CASE WHEN name = 'cola' OR name = 'fanta'
                    THEN 'soda' ELSE name END)) as count
FROM #MyTable
GROUP BY CASE WHEN name = 'cola' OR name = 'fanta'
                    THEN 'soda' ELSE name END


+-------+-------+
| name  | count |
+-------+-------+
| soda  | 8     |
+-------+-------+
| water | 3     |
+-------+-------+

我可以建议使用子查询:

SELECT name, count(*) AS count
FROM (SELECT CASE WHEN name = 'cola' OR name = 'fanta'
             THEN 'soda' ELSE name END as name
      FROM #MyTable) x
GROUP BY name;

答案 2 :(得分:0)

如果您需要聚合以及单个产品,则可以选择使用UNION并选择聚合作为第二个查询。

SELECT name,count(distinct id)as count 来自#MyTable GROUP BY名称

UNION

SELECT'SODA',COUNT(非常ID)作为计数 来自#MyTable 名称='可乐'或名称='芬达'

如果您需要更多分组,您也可以使用SørenHøyerKristensen的汇总表来获取汇总名称。