我正在尝试对别名列执行 group by 操作(如下所示),但无法确定正确的语法。
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
答案是肯定的,它仍然适用。
您传递要分组的表达式而不是别名
SELECT LastName + ', ' + FirstName AS 'FullName'
FROM customers
GROUP BY LastName + ', ' + FirstName
这就是我所做的。
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
不幸的是,你无法在 GROUP BY 语句中引用你的别名,你必须重新编写逻辑,这看起来很神奇。
SELECT LastName + ', ' + FirstName AS 'FullName'
FROM customers
GROUP BY LastName + ', ' + FirstName
或者,您可以将选择放入子选择或公共表表达式中,之后您可以对列名(不再是别名)进行分组。
抱歉,这对于 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
您可以使用
CROSS APPLY
创建别名并在 GROUP BY
子句中使用它,如下所示:
SELECT FullName
FROM Customers
CROSS APPLY (SELECT LastName + ', ' + FirstName AS FullName) Alias
GROUP BY FullName
鉴于您编辑的问题描述,我建议使用
COALESCE()
而不是那个笨拙的 CASE
表达式:
SELECT FullName
FROM (
SELECT COALESCE(LastName+', '+FirstName, FirstName) AS FullName
FROM customers
) c
GROUP BY FullName;
我的猜测是:
SELECT LastName + ', ' + FirstName AS 'FullName'
FROM customers
GROUP BY LastName + ', ' + FirstName
Oracle也有类似的限制,这很烦人。 我很好奇是否有更好的解决方案。
为了回答问题的后半部分,此限制也适用于更复杂的表达式,例如您的 case 语句。 我见过的最好的建议是使用子选择来命名复杂的表达式。
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
在这种情况下,“James Taylor”和“John Taylor”都会生成“J Taylor”。
如果您希望输出有两次“J Taylor”(每人一个):
GROUP BY LastName, FirstName
但是,如果您只想要一排“J Taylor”,您会想要:
GROUP BY LastName, LEFT(FirstName, 1)
如果您想避免 case 语句在查询中出现两次的混乱,您可能需要将其放置在用户定义函数中。
抱歉,SQL Server 不会在 Group By 子句之前呈现数据集,因此列别名不可用。您可以在 Order By 中使用它。
在旧的FoxPro(我从2.5版本开始就没有使用过它),你可以写这样的东西:
SELECT LastName + ', ' + FirstName AS 'FullName', Birthday, Title
FROM customers
GROUP BY 1,3,2
我真的很喜欢这种语法。为什么它没有在其他地方实施?这是一个很好的捷径,但我认为它会导致其他问题?
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)
(即 SQL Server 抱怨您没有在 Group By 或聚合函数中包含字段 Amount)
...记住在 SELECT 中放置完全相同的函数...
SELECT AccountNumber, ISNULL(Amount, 0) AS MyAlias
FROM Transactions
GROUP BY AccountNumber, ISNULL(Amount, 0)
在此处的答案中添加另一个变体,表明这也是 公用表表达式(CTE)的一个很好的用例。
WITH CustomersWithFullNames AS (
SELECT LastName + ', ' + FirstName AS FullName, *
FROM customers
)
SELECT FullName
FROM CustomersWithFullNames
GROUP BY FullName
在性能方面,这与内部子查询的工作方式相同,但是(至少对我来说)以自上而下的方式阅读起来更容易一些
旁注:一些数据库如snowflake允许您在group by子句中引用投影子句中的表达式