Поместите SQL — запрос в выражение case

#sql #sql-server #tsql

Вопрос:

Я хочу поставить

 SELECT DISTINCT ResidentGroup 
FROM Credits.ProductsPurposesBalanceGroups 
WHERE BalanceTypeID = 1`
 

внутри case выражения, потому что таблица Credits.ProductsPurposesBalanceGroups всегда меняется, и мне нужно проверить соответствие.

Когда я запускаю приведенный ниже код таким образом, я получаю эту ошибку:

Невозможно выполнить агрегатную функцию для выражения, содержащего агрегат или подзапрос

Как этого можно избежать или, может быть, есть другой способ сделать это?

 select 
    p.TypeName as 'Purpose', 
    sum((case 
            when tr.CurrencyID = 417 
                 and acc_credit.BalanceGroup in (select distinct ResidentGroup 
                                                 from Credits.ProductsPurposesBalanceGroups 
                                                 where BalanceTypeID = 1) 
               then tr.SumV 
               else 0 
         end)) as 'Pay417', 
    sum((case 
            when tr.CurrencyID = 840 
                 and acc_credit.BalanceGroup in (select distinct ResidentGroup 
                                                 from Credits.ProductsPurposesBalanceGroups 
                                                 where BalanceTypeID = 2) 
               then tr.SumV 
               else 0 
         end)) as 'Pay840', 
      -- and it goes that way until BalanceTypeID = 16"""

from 
    dbo.Transactions as tr 
inner join  
    dbo.Accounts as acc_credit on (tr.CreditAccountID = acc_credit.AccountNo)
group by 
    p.TypeName 
order by 
    p.TypeName
 

Комментарии:

1. CASE не выражение, а утверждение. T-SQL не поддерживает Case Switch операторы (), только CASE выражения.

2. Вместо того, чтобы выполнять (или лучше: пытаться выполнять) этот запрос снова и снова, я бы предложил переместить подзапрос SELECT DISTINCT ResidentGroup, BalanyceType... в cte, затем выполнить a LEFT JOIN в этот cte и изменить свой запрос на CASE WHEN [colname] IS NULL THEN 0 else [value] end

3. Посмотри на это dba.stackexchange.com/a/251671/187972

4. Примеры данных, желаемые результаты и объяснение «соответствия» действительно помогли бы. Я действительно понятия не имею, что вы пытаетесь сделать.

Ответ №1:

Следующее может решить проблему. Однако без каких-либо выборочных данных и т. Д. это трудно оценить…

 WITH cteResGrp AS(
  SELECT DISTINCT ResidentGroup, BalanceTypeID
    FROM Credits.ProductsPurposesBalanceGroups
)
select 
    p.TypeName as 'Purpose', 
    sum((case 
            when tr.CurrencyID = 417 
                 and rg.ResidentGroup IS NOT NULL 
               then tr.SumV 
               else 0 
         end)) as 'Pay417', 
    sum((case 
            when tr.CurrencyID = 840 
                 and rg.ResidentGroup IS NOT NULL 
               then tr.SumV 
               else 0 
         end)) as 'Pay840', 
      -- and it goes that way until BalanceTypeID = 16"""

from 
    dbo.Transactions as tr 
inner join  
    dbo.Accounts as acc_credit on tr.CreditAccountID = acc_credit.AccountNo
left join
    cteResGrp rg ON rg.ResidentGroup = acc_credit.BalanceGroup
                 AND (    (rg.BalanceTypeID = 1 AND tr.CurrencyID = 417)
                       OR (rg.BalanceTypeID = 2 AND tr.CurrencyID = 840)
                       OR ...
                     )
group by 
    p.TypeName 
order by 
    p.TypeName
 

См. Следующий пример скрипки: http://sqlfiddle.com/#!18/d580ae/3/1

Ответ №2:

Обходной путь состоит в том, чтобы сначала выбрать элемент строки, а затем агрегировать во втором проходе. Например, с CTE:

 --Lineitem
;WITH CTE AS (
select 
    p.TypeName as 'Purpose', 
         case 
            when tr.CurrencyID = 417 
                 and acc_credit.BalanceGroup in (select distinct ResidentGroup 
                                                 from Credits.ProductsPurposesBalanceGroups 
                                                 where BalanceTypeID = 1) 
               then tr.SumV 
               else 0 
         end as 'Pay417', 
         case 
            when tr.CurrencyID = 840 
                 and acc_credit.BalanceGroup in (select distinct ResidentGroup 
                                                 from Credits.ProductsPurposesBalanceGroups 
                                                 where BalanceTypeID = 2) 
               then tr.SumV 
               else 0 
         end as 'Pay840'
      -- and it goes that way until BalanceTypeID = 16"""

from 
    dbo.Transactions as tr 
inner join  
    dbo.Accounts as acc_credit on (tr.CreditAccountID = acc_credit.AccountNo)

.
.
.
) --End of CTE

--Aggregate lineitem
SELECT Purpose
      ,SUM(Pay417) AS [Pay417]
      ,SUM(Pay840) AS [Pay840]
  FROM CTE

group by 
    Purpose
order by 
    Purpose