#sql #oracle #case
#sql #Oracle #случай
Вопрос:
Допустим, у меня есть этот тип набора данных:
row Num_A Num_B Num_C Reg_1 Reg_2
------ ----- ----- ----- ----- -----
1 9400 9500 9700 AAA CCC
2 9700 9400 9500 BBB DDD
3 9500 9400 9200 EEE AAA
4 9100 9300 9900 AAA DDD
Рассмотрим следующие условия:
В строке 1 Num_B
"95000"
отображается в Num_A
(строка 3), а соответствующий Num_A
(строка 1) "94000"
равен его Num_B
(строка 3) (что имеет место `»94000″)
Таким образом, новый столбец Comm_1
будет иметь комбинацию Num_A
и Num_B
в качестве своего значения. То же самое касается Comm_2
Что касается Comm_3
, условие такое же, как Comm_1
или Comm_2
, и дополнительное условие, что Reg_1
(или Reg_2
) строки 1 'AAA'
(или 'CCC'
) равно Reg_1
или Reg_2
строки 3 (что имеет место).
Я хочу создать запрос так, чтобы результат выглядел следующим образом:
row Num_A Num_B Num_C Reg_1 Reg_2 Comm_1 Comm_2 Comm_3
------ ----- ----- ----- ----- ----- ----- ----- -----
1 9400 9500 9700 AAA CCC 94009500 94009700 94009500
2 9700 9400 9500 BBB DDD 97009400 97009500 NULL
3 9500 9400 9200 EEE AAA 95009400 NULL 95009400
4 9100 9300 9900 AAA DDD NULL NULL NULL
Я попробовал следующий базовый синтаксис, но он не работает:
SELECT
IF(Num_B in (select distinct Num_A from mydata) , concat(Num_A,Num_B), Null) as Comm_1,
IF(Num_C in (select distinct Num_A from mydata) , concat(Num_A,Num_C), Null) as Comm_2
FROM mydata
Поэтому, пожалуйста, предоставьте любую подсказку и укажите мне, чтобы я прочитал о правильном пункте pl/sql
или какой-либо процедуре, которую мне нужно изучить.
Комментарии:
1. Числа в ваших входных и выходных данных разные, и я не понимаю логику, которую вы пытаетесь применить. (Я действительно не уверен в том, что «корреспондент Num_A «94000» равен его Num_A» — это то, что должно быть «… его Num_B»?) Не могли бы вы отредактировать свой вопрос, чтобы уточнить, пожалуйста?
2. Какой результат вы получаете для вашего существующего запроса?
3. @SamChats, строка 4 получает
NULL
значение forComm_3
, потому что ни9300
одного или9900
(Num_B
иNum_C
) нет в спискеNum_A
4. @SamChats, это пример для строки 1, то же самое для остальных строк
5. Я не уверен, что это помогло, извините; и было бы лучше полностью объяснить в вопросе. Я не вижу ничего, что противоречит тому, что делают ответы; если они неверны, вам нужно объяснить, почему.
Ответ №1:
Вы можете получить то, что (я думаю) вы хотите с помощью внешних самосоединений:
-- CTE for sample data, including row_num to maintain display order
with mydata (row_num, Num_A, Num_B, Num_C, Reg_1, Reg_2) as (
select 1, 94000, 95000, 97000, 'AAA', 'CCC' from dual
union all select 2, 97000, 94000, 95000, 'BBB', 'DDD' from dual
union all select 3, 95000, 94000, 92000, 'EEE', 'AAA' from dual
union all select 4, 91000, 93000, 99000, 'AAA', 'DDD' from dual
)
-- actual query
select m.*,
case when m1.num_a is not null then m.num_a || m1.num_a end as comm_1,
case when m2.num_a is not null then m.num_a || m2.num_a end as comm_2,
case when m3.num_a is not null then m.num_a || m3.num_a end as comm_3
from mydata m
left join mydata m1 on m1.num_a = m.num_b
left join mydata m2 on m2.num_a = m.num_c
left join mydata m3 on m3.num_a = m.num_b and (m3.reg_1 = m.reg_2 or m3.reg_2 = m.reg_1)
order by m.row_num;
ROW_NUM NUM_A NUM_B NUM_C REG REG COMM_1 COMM_2 COMM_3
---------- ---------- ---------- ---------- --- --- ---------- ---------- ----------
1 94000 95000 97000 AAA CCC 9400095000 9400097000 9400095000
2 97000 94000 95000 BBB DDD 9700094000 9700095000
3 95000 94000 92000 EEE AAA 9500094000 9500094000
4 91000 93000 99000 AAA DDD
(Я оставил row_num
только для того, чтобы сохранить порядок отображения прежним, иначе он не используется; Я предполагаю, что на самом деле это не столбец в вашей таблице.)
comm_1
Значение основано на левом соединении с другой строкой, которая num_a
соответствует этой строке num_b
.
comm_2
Значение основано на левом соединении с другой строкой, которая num_a
соответствует этой строке num_c
.
comm_3
Значение такое же, как comm_1
, но также должно совпадать reg_1
с другим значением строки reg_2
или наоборот. Но при этом значение строки 3 вычисляется как 9500094000, а не как 94009500, показанное в вопросе, хотя неясно, что правильно.
Это также приведет к дублированию строк, если для любого из внешних соединений имеется более одного совпадения; это не относится к вашим образцам данных, но на что следует обратить внимание. Я понятия не имею, как вы хотели бы справиться с этим, если это может произойти.
Вы также можете сделать это с помощью одного внешнего соединения и дополнительной логики / агрегации в выражениях столбцов:
select m.row_num, m.num_a, m.num_b, m.num_c, m.reg_1, m.reg_2,
max(case when m1.num_a = m.num_b then m.num_a || m1.num_a end) as comm_1,
max(case when m1.num_a = m.num_c then m.num_a || m1.num_a end) as comm_2,
max(case when m1.num_a = m.num_b and (m1.reg_1 = m.reg_2 or m1.reg_2 = m.reg_1)
then m.num_a || m1.num_a end) as comm_3
from mydata m
left join mydata m1 on (m1.num_a = m.num_b) or (m1.num_a = m.num_c)
group by m.row_num, m.num_a, m.num_b, m.num_c, m.reg_1, m.reg_2
order by m.row_num;
ROW_NUM NUM_A NUM_B NUM_C REG REG COMM_1 COMM_2 COMM_3
---------- ---------- ---------- ---------- --- --- ---------- ---------- ----------
1 94000 95000 97000 AAA CCC 9400095000 9400097000 9400095000
2 97000 94000 95000 BBB DDD 9700094000 9700095000
3 95000 94000 92000 EEE AAA 9500094000 9500094000
4 91000 93000 99000 AAA DDD
Комментарии:
1. Хорошо, большое вам спасибо, это работает для моего примера, я прогоню его по набору данных hole с другими условиями (Num_A сгруппированы и некоторые другие проблемы), и я вернусь к вам, когда окончательный набор данных будет завершен, еще раз спасибо 🙂
2. Хорошо, спасибо, я запускаю его в базе данных whomle с некоторыми другими условиями, но с условием или reg не в инструкции join, а в случае, когда запрос, и он отлично сработал (иначе это заняло бы слишком много времени), еще раз спасибо 🙂
3. Но просто вопрос, когда нам нужно использовать циклы и pl / sql?
Ответ №2:
Если я правильно понял логику, вы могли бы использовать эти подзапросы:
select row_, Num_A, Num_B, Num_C, Reg_1, Reg_2,
(select min(m.num_a||' '||m.num_b) from mydata where num_a = m.num_b ) comm_1,
(select min(m.num_a||' '||m.num_c) from mydata where num_a = m.num_c ) comm_2,
(select min(m.num_a||' '||m.num_b) from mydata
where num_a = m.num_b and (reg_2 = m.reg_1 or reg_1 = m.reg_2)) comm_3
from mydata m
Я использовал min
в случае, если было много совпадающих строк.
Комментарии:
1. Хорошо, большое вам спасибо, это работает для моего примера, я прогоню его по набору данных hole с другими условиями (Num_A сгруппированы и некоторые другие проблемы), и я вернусь к вам, когда окончательный набор данных будет завершен, еще раз спасибо 🙂
2. хорошо, спасибо, но я выбрал первое решение, потому что оно намного быстрее, спасибо 🙂