Использование PL/SQL для запуска операции условного слияния
Правка. В исходном сообщении спрашивается, как преобразовать существующий набор данных в установленную таблицу (с именем PROFILES) с помощью подхода, который может решить SQL или PL/SQL.
Редактировать снова: Последний комментарий от OP был довольно тонким. Если у вас нет прямого доступа к SQL, вам в любом случае понадобится CURSOR
, управляющий запрос или какая-то другая конструкция для обработки каждой из ваших записей. Многие компоненты промежуточного программного обеспечения на основе JDBC также принимают курсоры в качестве входных данных. Вы можете ввести все свои данные в один вызов процедуры... взгляните на REF CURSOR
типов данных в PL/SQL. Если это так, это решение все еще может помочь.
Используя составной ключ соединения, обновите данные в целевой таблице на основе нескольких критериев:
INSERT
исходные данные, если они еще не существуют.
- Переключите или
UPDATE
значение статуса, если идентификатор человека (имя + фамилия) существует.
- Если человек уже существует в целевой таблице и уже имеет статус «активный», пропустите его.
Образец данных
Я назвал свои таблицы немного по-другому и изменил имя столбца «имя», которое является зарезервированным ключевым словом sql/plsql... для предотвращения любых возможных конфликтов в будущем.
Примеры операторов вставки данных (DML):
*Для ясности: имена в тестовой схеме не совсем соответствуют ОП. STACK_PROFILES
= PROFILES
, а STACK_PROFILE_MERGE_SOURCE
представляет "какой-то источник"... это мог быть xml-канал, текстовый файл csv и т. д. и т. д.
from: load_profile_data.sql...
CREATE TABLE "STACK_PROFILES"
( "PROFILE_NAME" VARCHAR2(40),
"SURNAME" VARCHAR2(40),
"ACTIVE" NUMBER(1,0),
CONSTRAINT "STACK_PROFILES_PK" PRIMARY KEY ("PROFILE_NAME", "SURNAME") ENABLE
)
INSERT INTO STACK_PROFILES (profile_name, surname, active) VALUES ('LOIS' , 'LAINE', 0);
INSERT INTO STACK_PROFILES (profile_name, surname, active) VALUES ('MARTIN', 'SHORT', 1);
INSERT INTO STACK_PROFILES (profile_name, surname, active) VALUES ('ROBIN' , 'WILLIAMS', 0);
INSERT INTO STACK_PROFILES (profile_name, surname, active) VALUES ('GRACE' , 'HOPPER', 0);
INSERT INTO STACK_PROFILES (profile_name, surname, active) VALUES ('LOIS' , 'LAINE-KENT', 0);
commit; ...
CREATE TABLE "STACK_PROFILE_MERGE_SOURCE"
( "PROFILE_NAME" VARCHAR2(40),
"SURNAME" VARCHAR2(40),
CONSTRAINT "STACK_PROFILE_MERGE_SOURCE_PK" PRIMARY KEY ("PROFILE_NAME", "SURNAME")
ENABLE
)
/
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('BRUCE' , 'WAYNE');
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('SPONGE' , 'ROBERT');
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('CLARK' , 'KENT');
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('LOIS' , 'LAINE');
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('MARTIN' , 'SHORT');
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('DAMON' , 'WAYANS');
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('ROBIN' , 'WILLIAMS');
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('BRUCE' , 'WILLIS');
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('DENNIS' , 'HOPPER');
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('WHOOPI' , 'GOLDBERG');
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('GRACE' , 'HOPPER');
INSERT INTO STACK_PROFILE_MERGE_SOURCE (profile_name, surname) VALUES ('JERI' , 'RYAN');
Тестовые случаи
Полезно понять представленные требования. Написание нескольких тестовых случаев приближает нас.
Для тестовых случаев 1 и 2...
![Условные тестовые примеры слияния 1,2](https://i.stack.imgur.com/vhWSY.png)
Для тестовых случаев 3 и 4...
![Условные тестовые случаи слияния 3,4](https://i.stack.imgur.com/yzZQU.png)
Исходный код PL/SQL
Существует более простой способ применить дополнительную условную логику с помощью функции, подобной SQL-слиянию. Следующий блок PL/SQL Anonymous использует outer join syntax
для идентификации записей, которые должны быть вставлены или обновлены. Третья категория (активная и уже присутствующая в целевой таблице) также наблюдается, поскольку цикл обработки курсора пропускает записи этого определения.
Цикл обработки и курсор
Мы используем синтаксис FOR UPDATE
и WHERE CURRENT OF
в операциях dml, потому что состояние данных, на которые ссылается этот запрос, изменяется в течение срока его использования.
declare
c_default_status_active constant number:= 1;
c_status_inactive constant number:= 0;
cursor profile_cur is
select sp.profile_name as target_name,
sp.surname as target_surname, sp.active as original_status,
spm.profile_name as source_name, spm.surname as source_surname
from stack_profiles sp, stack_profile_merge_source spm
where spm.profile_name = sp.profile_name(+)
and spm.surname = sp.surname(+)
order by spm.profile_name asc nulls last,
spm.surname asc
for update of sp.profile_name, sp.surname, sp.active;
v_rec_profile profile_cur%ROWTYPE;
begin
open profile_cur;
fetch profile_cur into v_rec_profile;
while profile_cur%found loop
-- insert condition (no match in outer join...)
if v_rec_profile.original_status is null
then
insert into stack_profiles (profile_name, surname, active)
values (v_rec_profile.source_name, v_rec_profile.source_surname,
c_default_status_active);
elsif
-- flip status from inactive to active for existing but
-- inactive records.
v_rec_profile.original_status = c_status_inactive then
update stack_profiles
set active = c_default_status_active
where current of profile_cur;
end if;
fetch profile_cur into v_rec_profile;
end loop;
close profile_cur;
commit;
end;
Обсуждение
I have noted many different approaches to this type of problem. The specific approach used here is to demonstrate the concept involved. Results may vary depending on the database configuration, its usage and set up.
person
Richard Pascual
schedule
26.06.2014
begin ... end;
? - person ThinkJet   schedule 26.06.2014