SQL Server: ошибка «недопустимое имя столбца» после GROUP BY в подзапросе - PullRequest
1 голос
/ 22 июня 2019

Я пытаюсь выполнить следующий запрос к таблице базы данных 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

Я получаю ошибку

MSSQLDatabaseException: (207, b "Неверное имя столбца 'user_payment_type'. Сообщение об ошибке DB-Lib 20018, серьезность 16: \ nОбщая ошибка SQL Server: проверка сообщений от SQL Server \ n")

Обратите внимание, что имя столбца user_payment_type уникально и не существует в MyTable.

Ответы [ 4 ]

1 голос
/ 22 июня 2019

Ваши SELECT и GROUP BY должны совпадать.Вы можете избежать дублирования кода, используя 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
1 голос
/ 22 июня 2019

Как уже отмечали другие, вы не можете ссылаться на псевдонимы столбцов в предложении group by, но должны также ссылаться на то же выражение.

Обратите внимание, что вы выполняете два расчета для одних и тех же данных. Вы можете выполнить оба вычисления в одном и том же подзапросе, чтобы сделать запрос короче и проще в обслуживании:

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
1 голос
/ 22 июня 2019

SQL Server не позволяет использовать этот столбец с псевдонимами в предложении group by (другие, например MySql, разрешают это), поскольку предложение group by выполняется перед выбором.
Вы должны использовать это утверждение 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
0 голосов
/ 22 июня 2019

Простой способ сделать это без вложенных подзапросов использует 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;

Это позволяет вам определять взаимозависимые определения без вложенных подзапросов или CTE или повторяющихся определений.

...