简体   繁体   English

SQL Server:子查询上的GROUP BY后出现“无效列名”错误

[英]SQL Server : “invalid column name” error after GROUP BY on subquery

I am trying to perform the following query on a SQL Server database table with a GROUP BY on a column which results from a CASE statement done on a subquery: 我试图在SQL Server数据库表上执行以下查询,在一个列上使用GROUP BY ,该列是在子查询上完成的CASE语句的结果:

SELECT
    AVG(sales) as avg_sales,
    COUNT(*) as total_sales,
    CASE
        WHEN (pay_method='cc') AND (user_type='subscriber') THEN 'cc-subscribed'
        WHEN (pay_method='cash') AND (user_type='subscriber') THEN 'cash-subscribed'
        ELSE 'standard'
    END as user_payment_type
FROM 
    (SELECT 
         column1, column2,
         UserType as user_type,
         CASE
            WHEN column1='something' AND column2='something_else' THEN 'cc'
            WHEN column1='something_else' AND column2='something' THEN 'cash'
         END as pay_method
    FROM MyTable) b
GROUP BY 
    user_payment_type

The error I am getting is 我得到的错误是

MSSQLDatabaseException: (207, b"Invalid column name 'user_payment_type'.DB-Lib error message 20018, severity 16:\\nGeneral SQL Server error: Check messages from the SQL Server\\n") MSSQLDatabaseException:(207,b“无效的列名'user_payment_type'.DB-Lib错误消息20018,严重级16:\\ n一般SQL Server错误:检查来自SQL Server的消息\\ n”)

Note that the column name user_payment_type is unique and does not already exist in MyTable . 请注意,列名user_payment_type是唯一的,并且在MyTable尚不存在。

SQL Server does not allow the use of this aliased column in the group by clause (others like MySql do allow it) because the group by clause is executed before select. SQL Server不允许在group by子句中使用此别名列(其他类似MySql允许它),因为group by子句在select之前执行。
You have to use that case statement: 你必须使用该case语句:

group by CASE
        WHEN (pay_method='cc') AND (user_type='subscriber') THEN 'cc-subscribed'
        WHEN (pay_method='cash') AND (user_type='subscriber') THEN 'cash-subscribed'
        ELSE 'standard'
    END

Your SELECT and GROUP BY should match. 您的SELECTGROUP BY应该匹配。 You could avoid duplicating code by using CROSS APPLY : 您可以使用CROSS APPLY避免重复代码:

WITH cte AS (
  SELECT column1,
         column2,
         UserType as user_type,
         CASE
             WHEN column1='something' AND column2='something_else' THEN 'cc'
             WHEN column1='something_else' AND column2='something' THEN 'cash'
         END as pay_method
    FROM MyTable
)
SELECT  AVG(c.sales) as avg_sales,
        COUNT(*) as total_sales,
        s.user_payment_type
FROM  cte c
CROSS APPLY (SELECT CASE
               WHEN (pay_method='cc') AND (user_type='subscriber') THEN 'cc-subscribed'
               WHEN (pay_method='cash') AND (user_type='subscriber') THEN 'cash-subscribed'
               ELSE 'standard' END) s(user_payment_type)
GROUP BY s.user_payment_type

As others have noted, you can't reference column aliases in the group by clause, but should reference the same expression there too. 正如其他人所指出的那样,你不能在group by子句中引用列别名,但也应该在那里引用相同的表达式。

Note, however, that you're performing two calculations on the same data. 但请注意,您正在对同一数据执行两次计算。 You could perform both calculations in the same subquery to make the query shorter and easier to maintain: 您可以在同一子查询中执行两个计算,以使查询更短且更易于维护:

SELECT
    AVG(sales) as avg_sales,
    COUNT(*) as total_sales,
    user_payment_type
FROM (
    SELECT sales,
           CASE
               WHEN column1 = 'something'      AND
                    column2 = 'something_else' AND /* These are the conditions for cc */
                    user_type = 'subscriber'
               THEN 'cc-subscribed'
               WHEN column1 = 'something_else' AND
                    column2 = 'something'      AND /* conditions for cash */
                    user_type = 'subscriber'
               THEN 'cash-subscribed'
               ELSE 'standard'
           END as user_payment_type
    FROM MyTable
) b
GROUP BY 
   user_payment_type

A simple way to do this without nested subqueries uses apply : 在没有嵌套子查询的情况下执行此操作的简单方法是使用apply

SELECT v1.user_payment_type,
       AVG(t.sales) as avg_sales,
       COUNT(*) as total_sales
FROM MyTable t CROSS APPLY
     (VALUES (CASE WHEN t.column1 = 'something' AND t.column2 = 'something_else' THEN 'cc'
                   WHEN t.column1 = 'something_else' AND t.column2 = 'something' THEN 'cash'
              END
             )
     ) v(pay_method) CROSS APPLY
     (VALUES (CASE WHEN v.pay_method = 'cc' AND t.user_type = 'subscriber' THEN 'cc-subscribed'
                   WHEN v.pay_method = 'cash' AND t.user_type = 'subscriber' THEN 'cash-subscribed'
                   ELSE 'standard'
              END)
     ) v1(user_payment_type)
GROUP BY v1.user_payment_type;

This allows you to define interdependent definitions without nesting subqueries or CTEs or repeating definitions. 这允许您定义相互依赖的定义,而无需嵌套子查询或CTE或重复定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM