Почему вы должны GROUP BY столбцы в инструкции CASE? - PullRequest
3 голосов
/ 25 июня 2009

Я пытаюсь выполнить запрос в SQL Server 2008 к таблице, в которую некоторые данные были введены непоследовательно, и я должен обработать это.

Пример таблицы данных:

OrderID   Qty   Price   MarkedUpTotal
1         10    1.00    11.00
1         -1    1.00    -1.10
1         -1    1.00    1.10

Мне нужно разобраться с ситуацией, когда Qty отрицательно, но MarkedUpTotal был введен как положительный.

Я бы хотел выполнить следующий запрос:

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN sum(-1*MarkedUpTotal) 
             ELSE SUM(MarkedUpTotal) END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

Однако при выполнении этого запроса я получаю следующую ошибку:

Колонка Qty недопустима в списке выбора, поскольку она не содержится ни в статистической функции, ни в предложении GROUP BY.

Столбец MarkedUpTotal недопустим в списке выбора, поскольку он не содержится ни в статистической функции, ни в предложении GROUP BY.

Мне нужен следующий результат:

OrderID    OrderTotalQty   InternalCost   ClientCost
1          8               8.00           8.80

Мне кажется странным, что я должен использовать GROUP BY Qty и MarkedUpTotal, когда они используются только условно оператором CASE. Если я удаляю последний выбор (оператор CASE), запрос выполняется нормально и не требует наличия Qty или Price в GROUP BY.

Почему SQL требует этого? Есть ли один запрос, который мог бы выполнить вышеуказанное?

В настоящее время я решаю проблему, используя временную таблицу. Я изменяю MarkedUpTotal каждой записи, если необходимо, а затем делаю простой SUM (MarkedUpTotal) в основном запросе из временной таблицы.

Ответы [ 5 ]

13 голосов
/ 25 июня 2009
SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        SUM(CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN -1*MarkedUpTotal
             ELSE MarkedUpTotal) END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

Причина, по которой она выдает ошибку, заключается в том, что вы СУММИРУЕТЕ ее внутри CASE - которая вернет 1 значение снаружи. Для SELECT с GROUP BY будет выглядеть, как будто вы передаете числовое значение (которое может быть константой или получено из другого источника) в виде столбца.

Подумайте о своем выражении SQL, похожем на это

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN 10
             ELSE 20 END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

Теперь возвращается новый столбец (ClientCost), который не использует агрегацию.
Итак, он просит вас использовать это в выражении GROUP BY.

1 голос
/ 25 июня 2009

Мне кажется странным, что я должен GROUP BY Qty и MarkedUpTotal, когда они используется только условно CASE Statement.

Я выделил ошибку ниже:

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        CASE WHEN Qty < 0 and MarkedUpTotal > 0   -- BOOM!!!!!!
             THEN sum(-1*MarkedUpTotal) 
             ELSE SUM(MarkedUpTotal) END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

SQL-сервер не знает, как оценить CASE WHEN Qty < 0 and MarkedUpTotal > 0. У вас есть 3 различных значения для этих записей в вашей таблице, что, как правило, не является проблемой, но поскольку вы группируете свои записи, выражение не имеет смысла, поскольку SQL-сервер не знает, какое из трех значений использовать при оценке выражение case, поэтому оно выдает недружественные пользователю ошибки синтаксического анализа, видимые в OP.

Все предложения кода в этой теме предоставляют решение.

1 голос
/ 25 июня 2009

Сделай так:

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        sum(CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN -1*MarkedUpTotal 
             ELSE MarkedUpTotal END) as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID
1 голос
/ 25 июня 2009

Ошибка об этой части. Какое значение строки Qty должен использовать Sql Server?

CASE WHEN Qty < 0 and MarkedUpTotal > 0 
    THEN sum(-1*MarkedUpTotal) 
    ELSE SUM(MarkedUpTotal) 
END as ClientCost

Вы можете переписать это как:

sum(CASE WHEN Qty < 0 and MarkedUpTotal > 0 
    THEN sum(-1*MarkedUpTotal) 
    ELSE SUM(MarkedUpTotal) 
END as ClientCost)

Или:

CASE WHEN sum(Qty) < 0 and sum(MarkedUpTotal) > 0 
    THEN sum(-1*MarkedUpTotal) 
    ELSE SUM(MarkedUpTotal) 
END as ClientCost

В зависимости от того, что вы имеете в виду:)

1 голос
/ 25 июня 2009

Имейте в виду, что результат оператора GROUP BY или оператора, в котором один или столбец использует статистическую функцию, содержит каждую строку, содержащую сводку других строк.

Используемое вами выражение CASE зависит от значений отдельных строк, а не от сводок; Вы можете ссылаться только на неагрегированные значения (то есть на значения в одной строке) в статистической функции или в предложении WHERE, поэтому решение будет включать размещение вашего CASE внутри агрегатной функции, в данном случае SUM.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...