如何对 SQLServer 中的别名列执行 GROUPBY?

我试图对别名列执行 分组操作(下面的例子) ,但是无法确定正确的语法。

SELECT       LastName + ', ' + FirstName AS 'FullName'
FROM         customers
GROUP BY     'FullName'

正确的语法是什么?

进一步扩展这个问题(我没有预料到我已经收到的答案) ,这个解决方案是否仍然适用于 CASEed 别名专栏?

SELECT
CASE
WHEN LastName IS NULL THEN FirstName
WHEN LastName IS NOT NULL THEN LastName + ', ' + FirstName
END AS 'FullName'
FROM         customers
GROUP BY
LastName, FirstName

答案是肯定的,它仍然适用。

154902 次浏览

传递要分组的表达式而不是别名

SELECT       LastName + ', ' + FirstName AS 'FullName'
FROM         customers
GROUP BY      LastName + ', ' + FirstName

遗憾的是,您不能在 GROUPBY 语句中引用别名,因此必须再次编写逻辑,尽管这看起来很神奇。

SELECT       LastName + ', ' + FirstName AS 'FullName'
FROM         customers
GROUP BY     LastName + ', ' + FirstName

或者,您可以将 select 放入子选择或公共表表达式中,然后可以对列名(不再是别名)进行分组

我的猜测是:

SELECT       LastName + ', ' + FirstName AS 'FullName'
FROM         customers
GROUP BY     LastName + ', ' + FirstName

Oracle 也有类似的限制,这令人恼火。我很好奇是否存在更好的解决方案。

为了回答问题的后半部分,这个限制也适用于更复杂的表达式,比如 case 语句。我看到的最好的建议是使用子选择来命名复杂表达式。

这就是我的工作。

SELECT FullName
FROM
(
SELECT LastName + ', ' + FirstName AS FullName
FROM customers
) as sub
GROUP BY FullName

这个技巧直接应用于你的“编辑”场景:

SELECT FullName
FROM
(
SELECT
CASE
WHEN LastName IS NULL THEN FirstName
WHEN LastName IS NOT NULL THEN LastName + ', ' + FirstName
END AS FullName
FROM customers
) as sub
GROUP BY FullName

对不起,这在 MS SQL Server 中是不可能的(但在 PostgreSQL 中是可能的) :

select lastname + ', ' + firstname as fullname
from person
group by fullname

否则就用这个:

select x.fullname
from
(
select lastname + ', ' + firstname as fullname
from person
) as x
group by x.fullname

或者这样:

select lastname + ', ' + firstname as fullname
from person
group by lastname, firstname  -- no need to put the ', '

上面的查询速度更快,首先对字段进行分组,然后对这些字段进行 计算分组。

下面的查询速度较慢(它首先尝试 计算选择表达式,然后根据该计算对记录进行分组)。

select lastname + ', ' + firstname as fullname
from person
group by lastname + ', ' + firstname

在旧版本的 FoxPro中(自从2.5版本以来我就没有使用过它) ,你可以这样写:

SELECT       LastName + ', ' + FirstName AS 'FullName', Birthday, Title
FROM         customers
GROUP BY     1,3,2

我真的很喜欢这句话。为什么没有在其他地方实现呢?这是个不错的捷径,但我想它会引起其他问题吧?

根据您编辑过的问题描述,我建议使用 COALESCE()而不是那个笨拙的 CASE表达式:

SELECT FullName
FROM (
SELECT COALESCE(LastName+', '+FirstName, FirstName) AS FullName
FROM customers
) c
GROUP BY FullName;
SELECT
CASE
WHEN LastName IS NULL THEN FirstName
WHEN LastName IS NOT NULL THEN LastName + ', ' + FirstName
END AS 'FullName'
FROM
customers
GROUP BY
LastName,
FirstName

这是因为您使用的公式(CASE 语句)不能为两个不同的输入给出相同的答案。

如果使用以下内容,情况就不是这样:

LEFT(FirstName, 1) + ' ' + LastName

在这种情况下,“詹姆斯 · 泰勒”和“约翰 · 泰勒”都会导致“ J · 泰勒”。

如果你想让你的输出有两个“ J Taylor”(每个人一个) :

GROUP BY LastName, FirstName

然而,如果你只想要一排“ J Taylor”,你会想要:

GROUP BY LastName, LEFT(FirstName, 1)

如果希望避免 case 语句在查询中出现两次混乱,可能需要将其放在 User-Definition-function 中。

对不起,SQLServer 不会在 Group By 子句之前呈现数据集,因此列别名不可用。你可以在订单中使用它。

SELECT
CASE WHEN LastName IS NULL THEN FirstName
WHEN LastName IS NOT NULL THEN LastName + ', ' + FirstName
END AS 'FullName'
FROM  customers GROUP BY 1`

对于那些发现自己有以下问题的人(通过确保零值和空值被等同对待来进行分组) ..。

SELECT AccountNumber, Amount AS MyAlias
FROM Transactions
GROUP BY AccountNumber, ISNULL(Amount, 0)

(例如,SQLServer 抱怨您没有在 GroupBy 或聚合函数中包含字段 Amount)

记住在你的 SELECT 中放置相同的函数。

SELECT AccountNumber, ISNULL(Amount, 0) AS MyAlias
FROM Transactions
GROUP BY AccountNumber, ISNULL(Amount, 0)

您可以使用 CROSS APPLY创建别名并在 GROUP BY子句中使用它,如下所示:

SELECT       FullName
FROM         Customers
CROSS APPLY  (SELECT LastName + ', ' + FirstName AS FullName) Alias
GROUP BY     FullName