#sql #sql-server #recursion
#sql #sql-сервер #рекурсия
Вопрос:
Первый запрос не выполняется, потому что у меня есть a SUM()
внутри a LAG()
, что просто незаконно, но я включил его просто для осмысления идеи.
SELECT
GUID_Key
,AFE_Number
,UWI
,Date
,ACT_NET_AMOUNT
,Cum_Act
,FC_NET_AMOUNT
,Cum_FC
,ROWNUM
,IIF(Cum_FC > Cum_Act, FC_NET_AMOUNT, Cum_Act-ISNULL(LAG(SUM(Cum_Act)OVER(PARTITION BY Date))OVER (ORDER BY ROWNUM),0)) AS Result
FROM ready_set
Или
SELECT
GUID_Key
,AFE_Number
,UWI
,Date
,ACT_NET_AMOUNT
,Cum_Act
,FC_NET_AMOUNT
,Cum_FC
,ROWNUM
,IIF(Cum_FC > Cum_Act, FC_NET_AMOUNT, IIF((LAG(CumRes) OVER( ORDER BY ROWNUM)) IS NULL, Cum_Act, Cum_Act - LAG(CumRes) OVER( ORDER BY ROWNUM))) AS Result
,IIF((LAG(CumRes) OVER( ORDER BY ROWNUM)) IS NULL ,/*Result*/IIF(Cum_FC > Cum_Act, FC_NET_AMOUNT, IIF((LAG(CumRes) OVER( ORDER BY ROWNUM)) IS NULL, Cum_Act, Cum_Act - LAG(CumRes) OVER( ORDER BY ROWNUM))), /*Result*/(IIF(Cum_FC > Cum_Act, FC_NET_AMOUNT, IIF((LAG(CumRes) OVER( ORDER BY ROWNUM)) IS NULL, Cum_Act, Cum_Act - LAG(CumRes) OVER( ORDER BY ROWNUM))) Lag(CumRes) OVER ( ORDER BY ROWNUM))) AS CumRes
FROM ready_set
Теперь я должен упомянуть, что в «ready_set» есть два нулевых столбца, result и CumRes, поэтому второй запрос даже выполняется.
Вот точная идея, показанная в электронной таблице Excel. В принципе, это не очень сложно, но, я думаю, это в программировании! Формула Excel той же идеи
РЕДАКТИРОВАТЬ: результаты формулы в Excel
В то же время я пытаюсь сохранить текущую сумму результатов в CumRes и вычислить результаты на основе предыдущего кумулятивного значения. Они взаимозависимы, поэтому я не могу просто суммировать результаты, чтобы получить столбец CumRes. Я не совсем понимаю, как SQL генерирует строки, и у меня может быть совершенно неправильный подход, если я пытаюсь отстать от столбца, который находится в процессе создания, а не уже существующего. Вы видите мою проблему или ошибку в мышлении?
Комментарии:
1. Пожалуйста, предоставьте примеры данных, желаемые результаты и четкое объяснение логики, которую вы хотите реализовать.
2. Чтобы вложить оконные агрегаты, вы должны вложить Selects, то есть либо производную таблицу, либо общее табличное выражение.
3. @GordonLinoff. Извините, я не могу предоставить вам эти фактические данные, поскольку они конфиденциальны. Как бы вам понравились образцы данных? В каком формате? Ссылка внизу показывает формулу, и я добавил дополнительное изображение с результатами этих формул.
4. @dnoeth Если возможно вложить их, как вы говорите, не могли бы вы объяснить немного больше или указать мне направление, где я мог бы узнать больше?
5. Я предполагаю, что ваш результат может быть достигнут простым способом. Можете ли вы подробнее рассказать о логике, основанной на
FC_NET_AMOUNT
иACT_NET_AMOUNT
? (cum_act
иcum_fc
, похоже, являются совокупными суммами этих столбцов плюс ROW_NUMBER)
Ответ №1:
Похоже, это соответствует вашим формулам:
with cte as
(
select ACC_NET_AMOUNT, fc_NET_AMOUNT
-- cumulative sums up to the previous rows
, coalesce(sum(ACC_NET_AMOUNT) over (order by rownum rows between unbounded preceding and 1 preceding) ,0) as cumacc
, coalesce(sum( FC_NET_AMOUNT) over (order by rownum rows between unbounded preceding and 1 preceding), 0) as cumfc
from tableX
)
select ACC_NET_AMOUNT, fc_NET_AMOUNT
, ca.CumResult - case when cumfc > cumacc then cumfc else cumacc end as Result
, ca.CumResult
from cte
cross apply
( select
case when cumfc FC_NET_AMOUNT > cumacc ACC_NET_AMOUNT
then cumfc FC_NET_AMOUNT
else cumacc ACC_NET_AMOUNT
end as CumResult) as ca
См . Скрипку
Комментарии:
1. Спасибо, Dnoeth! На самом деле это работает лучше с меньшим количеством настроек! Спасибо!
Ответ №2:
create table tableX (rownum int not null,
ACC_NET_ int not null, CumACT int not null,
FC_NET_AMOUNT int not null, CumFC int not null);
insert into tableX (rownum, ACC_NET_, CumACT, FC_NET_AMOUNT, CumFc) values
(1, 40, 40, 50, 50), (2, 164, 204, 2050, 2100), (3, 1513, 1717, 0, 2100),
(4, 1000, 2717, 500, 2600), (5, 100, 2817, 0, 2600);
go
with iterated as (
select rownum, ACC_NET_, CumACT, FC_NET_AMOUNT, CumFc,
iif(CumFc > CumACT, FC_NET_AMOUNT, CumACT - 0) as result,
0 as CumRes
from tableX
where rownum = 1
union all
select x.rownum, x.ACC_NET_, x.CumACT, x.FC_NET_AMOUNT, x.CumFc,
f.result,
f.result anchor.CumRes
from iterated as anchor inner join tableX x
on x.rownum = anchor.rownum 1
cross apply (
select iif(x.CumFc > x.CumACT, x.FC_NET_AMOUNT, x.CumACT - anchor.CumRes)
) as f(result)
)
select * from iterated;
Рекурсивный запрос будет работать для ваших формул. Возможно, вам потребуется прочитать больше об этой теме, если проблема больше, чем указано в ваших данных выше. Также мне пришлось добавить rownum
столбец, чтобы иметь возможность упорядочивать строки по порядку.
РЕДАКТИРОВАТЬ: я неправильно ввел одно из начальных значений, и это было исправлено.
Комментарии:
1. Спасибо! Это отлично работает само по себе, и я пытаюсь заставить его работать в моем запросе, но безуспешно. Я пометил это как ответ, потому что считаю, что у меня есть другие проблемы, которые мне нужно выяснить, но это четко отвечает на мой вопрос. Однако я использую другие CTE в своем запросе, и я продолжаю получать сообщение об ошибке «Типы не совпадают между привязкой и рекурсивной частью в столбце «CumRes» рекурсивного запроса «iterated»». Возможно, потому, что result_set является cte, а не таблицей, подобной примеру, который вы мне дали? Я не совсем уверен.
2. Существуют ограничения на рекурсивные запросы, которые могут применяться. Я подозреваю, что ошибка означает, что столбцы в объединении выстроены неправильно или что вам, по крайней мере, нужно выполнить преобразование, чтобы сделать их совместимыми.
3. Я понял, что мне пришлось также использовать Result как float в дополнение к CumRes, потому что после его добавления в CumRes тип больше не соответствует! Я бы поддержал ваш ответ, если бы у меня было 15 повторений, ха-ха! В итоге я также использовал временную таблицу, потому что она лучше соответствовала моим потребностям. Спасибо миллион @shawnt00
4. Рад, что вы поняли это. Вы, конечно, можете вернуться и проголосовать позже, если захотите.
Ответ №3:
Если вам нужна совокупная сумма:
select rs.*, sum(fc_net_amount) over (order by rownum)
from ready_set rs
Комментарии:
1. Спасибо, столбцы могут иметь не самое лучшее название, но Cum_FC — это совокупная сумма FC_NET_AMOUNT . Это не проблема, с которой я сталкиваюсь.