如何在TSQL中按表达式分组并捕获结果?

时间:2017-10-13 22:51:53

标签: sql tsql sql-server-2012 group-by

如何在GROUP BY子句中包含表达式的结果,还可以选择表达式的输出?

说我有这张桌子:

╔════════════════════════╦═══════════╦═══════╗
║         Forest         ║  Animal   ║ Count ║
╠════════════════════════╬═══════════╬═══════╣
║ Tongass                ║ Hyena     ║   600 ║
║ Tongass                ║ Bear      ║  1200 ║
║ Mount Baker-Snoqualmie ║ Wolf      ║    30 ║
║ Mount Baker-Snoqualmie ║ Bunny     ║     2 ║
║ Ozark-St. Francis      ║ Pigeon    ║   100 ║
║ Ozark-St. Francis      ║ Ostrich   ║     1 ║
║ Bitterroot             ║ Tarantula ║  9001 ║
╚════════════════════════╩═══════════╩═══════╝

我需要在每个森林中加入食肉动物的数量,并计算非食肉动物数量(如果有的话)。这是我在这个例子中寻找的输出:

╔════════════════════════╦═══════════════╦═══════════════╗
║         Forest         ║ AnimalsOfType ║ AreCarnivores ║
╠════════════════════════╬═══════════════╬═══════════════╣
║ Tongass                ║          1800 ║             1 ║
║ Mount Baker-Snoqualmie ║             2 ║             0 ║
║ Mount Baker-Snoqualmie ║            30 ║             1 ║
║ Ozark-St. Francis      ║           101 ║             0 ║
║ Bitterroot             ║          9001 ║             1 ║
╚════════════════════════╩═══════════════╩═══════════════╝

动物是否具有食肉性的信息编码在表达式中。

我想要做的是在group-by中包含表达式并在select子句中引用它的结果:

SELECT TOP (1000)
    [Forest],
    SUM([COUNT]) AS AnimalsOfType,
    AreCarnivores
FROM [Tinker].[dbo].[ForestAnimals]
GROUP BY
    Forest,
    CASE WHEN ForestAnimals.Animal IN ('Pigeon', 'Ostrich', 'Bunny') THEN 0 ELSE 1 END AS AreCarnivores

但是,这不是有效的TSQL语法。

如果我在GROUP BY子句中包含Animal列以允许我在SELECT中重新运行该函数,那么每个动物类型都会得到一行,这不是所希望的行为。

单独选择临时表并将结果联合起来是不可取的,因为此查询的真实版本具有大量表达式,这些表达式在同一结果集中需要此行为,这将导致非常笨拙的存储过程。

1 个答案:

答案 0 :(得分:2)

使用CTE:

WITH X AS (
  SELECT Forest, Animal, Count,
         CASE WHEN ForestAnimals.Animal IN ('Pigeon', 'Ostrich', 'Bunny') 
              THEN 0 
              ELSE 1 END AS AreCarnivores
  FROM [Tinker].[dbo].[ForestAnimals]
)
SELECT Forest, SUM(Count) AS AnimalsOfType, AreCarnivores
FROM X
Group by Forest, AreCarnivores;

或者对此更加冗长并重复自己:

SELECT   Forest, SUM(Count) AS AnimalsOfType, 
         CASE WHEN ForestAnimals.Animal IN ('Pigeon', 'Ostrich', 'Bunny') 
              THEN 0 
              ELSE 1 END AS AreCarnivores
FROM [Tinker].[dbo].[ForestAnimals]
GROUP BY Forest, CASE WHEN ForestAnimals.Animal IN ('Pigeon', 'Ostrich', 'Bunny') 
                 THEN 0 
                 ELSE 1 END;

他们对优化程序提出了相同的查询。