Intereting Posts
MySQL – вставить текущую дату / время? GROUP BY с датой MAX SQL Query для подсчета количества заказов на одного клиента и суммарной суммы доллара Доступ к псевдониму столбцов в postgresql CREATE FILE обнаружил ошибку операционной системы 5 (не удалось получить текст для этой ошибки. Причина: 15105) Генерировать данные для диапазона дат, в том числе тех, которые отсутствуют в данных Ошибка MySQL в наибольшей степени на группу Явное vs неявное объединение SQL Любое влияние производительности на Oracle для использования LIKE 'string' vs = 'string'? SQL SELECT ORDER BY несколько столбцов в зависимости от значения другого столбца Операция не разрешена после закрытия ResultSet (mysql, java) немонотонные SQL-запросы SQL – возвращает 0s, если не существует группы Определение максимального значения с нулевой датой между двумя столбцами в db2 SQL REGEXP_SUBSTR возвращает null String при расщеплении

Вычисление в двух столбцах разной строки в sql

У меня есть таблица t1

ID NAME AGE GENDER BALANCE ----- ----- --------- ----- --------- 1001 John 10 M 10 1002 Meena 5 F 0 1003 Nikh 11 M 0 1004 divs 7 F 0 1005 neha 4 F 0 

из второй строки, если «Пол» равен «М», тогда «Баланс» (2-я строка) должен быть возрастом (2) + баланс (1)

else Balance (1) -age (2)

Окончательная структура должна

 ID NAME AGE GENDER BALANCE ----- ----- --------- ----- --------- 1001 John 10 M 10 1002 Meena 5 F 5 1003 Nikh 11 M 16 1004 divs 7 F 9 1005 neha 4 F 5 

Пожалуйста, помогите мне с запросом / процедурой

Как насчет чего-то подобного?

 with sample_data as (select 1001 id, 'John' name, 10 age, 'M' gender, 10 balance from dual union all select 1002 id, 'Meena' name, 5 age, 'F' gender, 0 balance from dual union all select 1003 id, 'Nikh' name, 11 age, 'M' gender, 0 balance from dual union all select 1004 id, 'divs' name, 7 age, 'F' gender, 0 balance from dual union all select 1005 id, 'neha' name, 4 age, 'F' gender, 0 balance from dual) select id, name, age, gender, sum(case when gender = 'F' then -1 * age else age end) over (order by id) balance from sample_data; ID NAME AGE GENDER BALANCE ---------- ----- ---------- ------ ---------- 1001 John 10 M 10 1002 Meena 5 F 5 1003 Nikh 11 M 16 1004 divs 7 F 9 1005 neha 4 F 5 

Я предполагаю, что баланс первой строки (я принимаю порядок id, здесь) равен 10, потому что это возраст Джона, а он мужчина, а не какое-то произвольное число.


ETA: вот альтернативы вышеуказанному решению. Я настоятельно рекомендую вам протестировать все на производственный объем данных (где я использовал предложение with, чтобы имитировать таблицу с именем sample_data с 5 строками, вам просто нужно будет использовать вашу таблицу). Таким образом, вы можете получить тайминги, которые должны выделить наиболее эффективный метод для вашего сценария; надеюсь, ваш менеджер не будет слепым к фактам (если он, бегите, бегите быстро!)

1) оператор SQL без аналитических функций:

 with sample_data as (select 1001 id, 'John' name, 10 age, 'M' gender, 10 balance from dual union all select 1002 id, 'Meena' name, 5 age, 'F' gender, 0 balance from dual union all select 1003 id, 'Nikh' name, 11 age, 'M' gender, 0 balance from dual union all select 1004 id, 'divs' name, 7 age, 'F' gender, 0 balance from dual union all select 1005 id, 'neha' name, 4 age, 'F' gender, 0 balance from dual) select sd1.id, sd1.name, sd1.age, sd1.gender, sum(case when sd2.gender = 'F' then -1 * sd2.age else sd2.age end) balance from sample_data sd1 inner join sample_data sd2 on (sd1.id >= sd2.id) group by sd1.id, sd1.name, sd1.age, sd1.gender order by id; ID NAME AGE GENDER BALANCE ---------- ----- ---------- ------ ---------- 1001 John 10 M 10 1002 Meena 5 F 5 1003 Nikh 11 M 16 1004 divs 7 F 9 1005 neha 4 F 5 

2) Процедурный (медленно-медленный ряд-рядный {yawn}) метод (НЕ рекомендуется):

 create or replace procedure calc_balance1 as v_balance number := 0; cursor cur is with sample_data as (select 1001 id, 'John' name, 10 age, 'M' gender, 10 balance from dual union all select 1002 id, 'Meena' name, 5 age, 'F' gender, 0 balance from dual union all select 1003 id, 'Nikh' name, 11 age, 'M' gender, 0 balance from dual union all select 1004 id, 'divs' name, 7 age, 'F' gender, 0 balance from dual union all select 1005 id, 'neha' name, 4 age, 'F' gender, 0 balance from dual) select id, name, age, gender, balance from sample_data; begin for rec in cur loop v_balance := v_balance + case when rec.gender = 'F' then -1 * rec.age else rec.age end; dbms_output.put_line('id = '||rec.id||', name = '||rec.name||', age = '||rec.age||', gender = '||rec.gender||', balance = '||v_balance); end loop; end calc_balance1; / begin calc_balance; end; / id = 1001, name = John, age = 10, gender = M, balance = 10 id = 1002, name = Meena, age = 5, gender = F, balance = 5 id = 1003, name = Nikh, age = 11, gender = M, balance = 16 id = 1004, name = divs, age = 7, gender = F, balance = 9 id = 1005, name = neha, age = 4, gender = F, balance = 5 

Однако, если вам приходилось придумывать процедуру для этого, я бы использовал запрос с аналитической функцией и просто вставлял его в курсор ref, например:

 create or replace procedure calc_balance2 (p_refcur out sys_refcursor) as begin open p_refcur for with sample_data as (select 1001 id, 'John' name, 10 age, 'M' gender, 10 balance from dual union all select 1002 id, 'Meena' name, 5 age, 'F' gender, 0 balance from dual union all select 1003 id, 'Nikh' name, 11 age, 'M' gender, 0 balance from dual union all select 1004 id, 'divs' name, 7 age, 'F' gender, 0 balance from dual union all select 1005 id, 'neha' name, 4 age, 'F' gender, 0 balance from dual) select id, name, age, gender, sum(case when gender = 'F' then -1 * age else age end) over (order by id) balance from sample_data order by id; end calc_balance2; / 

——————

Я вижу процедуру, которую вы написали; вот как бы я это сделал:

 -- mimicking your test_divs table: create table test_divs as select 1001 id, 'John' name, 10 age, 'M' gender, 10 balance from dual union all select 1002 id, 'Meena' name, 5 age, 'F' gender, 0 balance from dual union all select 1003 id, 'Nikh' name, 11 age, 'M' gender, 0 balance from dual union all select 1004 id, 'divs' name, 7 age, 'F' gender, 0 balance from dual union all select 1005 id, 'neha' name, 4 age, 'F' gender, 0 balance from dual; create or replace procedure t1_d12_v2 as begin merge into test_divs tgt using (select id, name, age, gender, sum(case when gender = 'F' then -1 * age else age end) over (order by id) balance from test_divs) src on (tgt.id = src.id) when matched then update set tgt.balance = src.balance; end t1_d12_v2; / select * from test_divs; ID NAME AGE GENDER BALANCE ---------- ----- ---------- ------ ---------- 1001 John 10 M 10 1002 Meena 5 F 0 1003 Nikh 11 M 0 1004 divs 7 F 0 1005 neha 4 F 0 begin t1_d12_v2; commit; end; / select * from test_divs; ID NAME AGE GENDER BALANCE ---------- ----- ---------- ------ ---------- 1001 John 10 M 10 1002 Meena 5 F 5 1003 Nikh 11 M 16 1004 divs 7 F 9 1005 neha 4 F 5 

Я НАСТОЯТЕЛЬНО предлагаю вам протестировать оба метода с вашими производственными данными и посмотреть, какой из них лучше работает. (Если ваш менеджер действительно мертв, установленный против аналитической функции, я бы заменил подзапрос «src» на другое заявление sql, с которым я столкнулся – тот, у кого есть соединение и группа.)

Выполнение обновлений по строкам, как и вы, будет заключаться в том, чтобы переключаться между sql и pl / sql дважды на каждый проход через цикл. Зачем беспокоиться, когда вы могли бы сделать все это в одном заявлении sql. Шутки в сторону.