#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, затем выполнить aLEFT 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