none
Проблема с использованием подзапросов в конструкции CASE RRS feed

  • Вопрос

  • Доброй ночи! Столкнулся с проблемой использования конструкции CASE вместо IF. Условия таковы, что от использования хранимых процедур, внутри которых использовался IF, пришлось отказаться, так как стороннее приложение, которое их вызывает (если кому интересно это Dundas Dashboard), очень 'своеобразно' их выполняет и происходит большая потеря в производительности.

    В связи с этим, по рекомендации разработчиков стороннего приложения было рекомендовано отказаться от использования хранимок и запускать запросы, находящиеся внутри них непосредственно из самого приложения. Однако тут возникает еще одна сложность: в самом Dundas интепретатор PL/SQL ограничен, и не позволяется использовать конструкцию IF. В тоже время CASE позволяет. В связи с этим запрос стал подобный этому и неработоспособный:

     

    select (

    case

    when (@MPCKey = 0 or @MPCKey is null) then

    case

    WHEN ((@Flag<>'' and @Flag is not null)

    and (@Name='' or @Name is null)) then

    (SELECT TOP 1 SUM(Amount) as Sales, SUM(Units) as Units, 

    (SUM(Amount)-SUM(NewAmount))/SUM(Amount) as GrossMargin

    --SUM(NewAmount) as COGS

    FROM dbo.AllAmount fds

    inner join PC.DimStores ds on ds.StoreKey=fds.StoreKey and ds.Flag=@Flag

    WHERE DateKey>=@Start and DateKey<=@End )

    WHEN ((@Flag = '' or @Flag is null) 

    and (@Name='' or @Name is null)) then

    (SELECT SUM(Amount) as Sales, SUM(Units) as Units, 

    (SUM(Amount)-SUM(NewAmount))/SUM(Amount) as GrossMargin

    FROM dbo.AllAmount fds

    WHERE DateKey>=@Start and DateKey<=@End)

    WHEN ((@Flag<>'' and @Flag is not null) 

    and (@Name<>'' and @Name is not null)) then

    (SELECT SUM(Amount) as Sales, SUM(Units) as Units, 

    (SUM(Amount)-SUM(NewAmount))/SUM(Amount) as GrossMargin

    FROM dbo.AllAmount fds

    inner join PC.DimStores ds on ds.StoreKey=fds.StoreKey and ds.Flag=@Flag

    and ds.Name=@Name

    WHERE DateKey>=@Start and DateKey<=@End)

    WHEN ((@Flag = '' or @Flag is null) 

    and (@Name<>'' and @Name is not null)) then

    (SELECT SUM(Amount) as Sales, SUM(Units) as Units, 

    (SUM(Amount)-SUM(NewAmount))/SUM(Amount) as GrossMargin

    FROM dbo.AllAmount fds

    inner join PC.DimStores ds on ds.StoreKey=fds.StoreKey and ds.Name=@Name

    WHERE DateKey>=@Start and DateKey<=@End)

    END

    END

    )

     

    В ответ на него получаю следующую ошибку:

     

    Msg 116, Level 16, State 1, Line 20

    Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.

    Msg 116, Level 16, State 1, Line 29

    Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.

    Msg 116, Level 16, State 1, Line 37

    Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.

    Msg 116, Level 16, State 1, Line 44

    Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.

    Подскажите плиз как можно решить эту проблему или же в таком контексте использование CASE невозможно?

    Ps: использование вместо конструкции WHEN логических конструкций как-то не подходит, так как у меня они работают медленней,

    чем хранимка.

     

    Заранее, спасибо за ответы.

    8 июня 2011 г. 22:51

Ответы

  • Добрый день! Сам себе отвечу на вопрос: проблема была решена следующим образом: внутри инструкции THEN запрос должен содержать в SELECT'е только одно поле, т.е.

    SELECT SUM(Amount) as Sales

    и ничего больше.

    Однако производительность CASE по сравнению с IF ниже в разы. Так что буду искать другие варианты, скорее всего логические конструкции внутри WHERE.

    Спасибо за внимание.


    • Помечено в качестве ответа Abolmasov Dmitry 14 июня 2011 г. 19:52