【问题标题】:SQL Server 2005 Group by aliasSQL Server 2005 按别名分组
【发布时间】:2013-03-08 22:19:47
【问题描述】:

我有

 select CustID,

case permission
When 'read' then 'X'
end as 'Read',

case permission
when 'write' then 'X'
end as 'Write',

case permission
when 'own' then 'X'
end as 'Own',

case permission
when ‘destroy’ then ‘X’
end as ‘Destroy’

from rights

group by custID, permission

我只想为每个 custID 写一行。相反,我得到:

CustID    |  Read | Write |  Own | Destroy

208345482     X     NULL    NULL   NULL| 
208345482    NULL   NULL     X     NULL|
208345482    NULL   NULL    NULL      X|
208345482    NULL    X      NUL    NULL|
8093657522   NULL   NULL    NULL     X|
8093657522   NULL   NULL     X    NULL|

我尝试按别名子查询进行分组,但无济于事。任何帮助将不胜感激。

【问题讨论】:

    标签: sql sql-server sql-server-2005 group-by


    【解决方案1】:

    您不能在GROUP BY 中使用别名,因为它在应用别名之前已被解析。唯一可以使用别名的地方是 ORDER BY 子句,因为它是在 SELECT 之后解析的唯一子句,其中定义了别名。

    典型的解决方法是重复GROUP BY 子句中的表达式:

    SELECT x = CASE ... END, SUM(something)
      FROM dbo.somewhere
      GROUP BY CASE ... END;
    

    或使用 CTE:

    ;WITH src AS
    (
      SELECT x = CASE ... END, something
        FROM dbo.somewhere
    )
    SELECT x, SUM(something)
      FROM src
      GROUP BY x;
    

    或者使用子查询:

    SELECT x, SUM(something)
      FROM
      (
        SELECT x = CASE ... END, something
          FROM dbo.somewhere
      ) AS src
      GROUP BY x;
    

    这些都应该进行类似的优化,但您应该测试您的特定场景以确定。

    在你的情况下,你可以这样写:

    SELECT CustID,
      [Read]    = MAX(CASE permission WHEN 'read'    THEN 'X' END),
      [Write]   = MAX(CASE permission WHEN 'write'   THEN 'X' END),
      [Own]     = MAX(CASE permission WHEN 'own'     THEN 'X' END),
      [Destroy] = MAX(CASE permission WHEN 'destroy' THEN 'X' END)
    FROM dbo.rights
    GROUP BY custID;
    

    或者像这样:

    SELECT CustID,
      MAX([Read]), MAX([Write]), MAX([Own]), MAX([Destroy])
    FROM
    (
      SELECT CustID,
       [Read]    = CASE permission WHEN 'read'    THEN 'X' END,
       [Write]   = CASE permission WHEN 'write'   THEN 'X' END,
       [Own]     = CASE permission WHEN 'own'     THEN 'X' END,
       [Destroy] = CASE permission WHEN 'destroy' THEN 'X' END
      FROM dbo.rights
    ) AS src
    GROUP BY custID;
    

    请不要使用单引号分隔列或表'alias'。不仅不推荐使用语法,而且还使实体看起来像字符串文字。如果必须对其进行转义(例如,如果您选择了错误的列名),请使用 [square brackets]

    【讨论】:

    • "您不能在 GROUP BY 中使用别名,因为它是在应用别名之前解析的。"但是为什么在应用别名之前就解析了呢?
    • @anario 我不知道我是否真的能告诉你原因,除了 SQL Server 的工作方式。 (我相信 MySQL 在这方面稍微宽松一些,但大多数真实平台应该更严格地遵守该标准。)关于this questionthis question 的更多细节在 dba.se 上。
    • 有用的链接,我现在很满意:)
    【解决方案2】:

    您可以在一个查询中直接使用PIVOT 表运算符来执行此操作,而不是使用这些CASE 表达式。

    它将执行您正在寻找的进一步步骤,即使用CASE 表达式传播记录后对记录进行分组。比如:

    SELECT 
      CustId, 
      read, 
      write, 
      own, 
      Destroy
    FROM
    ( 
       SELECT custid, permission, x
       FROM tablename
    ) AS t
    PIVOT
    (
       MAX(x)
       FOR permission IN('read', 
                         'write', 
                         'own', 
                         'Destroy')
    ) AS p;
    

    在您的查询中,如果x 是字符串文字而不是标识符,那么您可以在锚查询SELECT custid, permission, 'x' AS x FROM tablename 中正常选择它作为带有别名的字符串文字,那么上面的查询应该可以正常工作。

    【讨论】:

      猜你喜欢
      • 2010-10-10
      • 2015-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多