Oracle Insert via Select из нескольких таблиц, где одна таблица может не иметь строки
У меня есть несколько таблиц значений кода, которые содержат код и описание с длинным идентификатором.
теперь я хочу создать запись для типа учетной записи, которая ссылается на ряд кодов, поэтому у меня есть что-то вроде этого:
insert into account_type_standard (account_type_Standard_id,
tax_status_id, recipient_id)
( select account_type_standard_seq.nextval,
ts.tax_status_id, r.recipient_id
from tax_status ts, recipient r
where ts.tax_status_code = ?
and r.recipient_code = ?)
это извлекает соответствующие значения из таблиц tax_status и recipient, если найдено совпадение для их соответствующих кодов. К сожалению, recipient_code является недействительным, и поэтому ? подстановка значений может быть null. Конечно, неявное соединение не возвращает строку, поэтому строка не вставляется в мою таблицу.
Я пробовал использовать NVL на ? и на р. recipient_id.
Я попытался заставить внешнее соединение на r.recipient_code = ? добавив ( + ), Но это не явное соединение, поэтому Oracle по-прежнему не добавила еще одну строку.
кто-нибудь знает способ сделать это?
Я, очевидно, могу изменить оператор так, чтобы я делал поиск recipient_id извне и имел ? вместо r.recipient_id, и не выбирайте из таблицы получателей вообще, но я бы предпочел сделать все это в 1 инструкции SQL.
6 ответов
внешние соединения не работают "как ожидалось" в этом случае, потому что вы явно сказали Oracle, что вам нужны данные, только если эти критерии в этой таблице совпадают. В этом случае соединение outter становится бесполезным.
обойти
INSERT INTO account_type_standard
(account_type_Standard_id, tax_status_id, recipient_id)
VALUES(
(SELECT account_type_standard_seq.nextval FROM DUAL),
(SELECT tax_status_id FROM tax_status WHERE tax_status_code = ?),
(SELECT recipient_id FROM recipient WHERE recipient_code = ?)
)
[редактирование] Если вы ожидаете несколько строк из под-выбора, вы можете добавить ROWNUM=1 к каждому предложению where или использовать агрегат, такой как MAX или MIN. Это, конечно, может быть не лучшим решением для всех случаев.
[Edit] Per комментарий
(SELECT account_type_standard_seq.nextval FROM DUAL),
можно просто
account_type_standard_seq.nextval,
немного упрощенная версия решения Oglester (последовательность не требует выбора из DUAL:
INSERT INTO account_type_standard
(account_type_Standard_id, tax_status_id, recipient_id)
VALUES(
account_type_standard_seq.nextval,
(SELECT tax_status_id FROM tax_status WHERE tax_status_code = ?),
(SELECT recipient_id FROM recipient WHERE recipient_code = ?)
)
мне не было ясно в вопросе, если ts.tax_status_code является первичным или альтернативным ключом или нет. То же самое с recipient_code. Это было бы полезно знать.
вы можете иметь дело с возможностью того, что ваша переменная bind будет нулевой, используя или следующим образом. Вы бы привязали то же самое к первым двум переменным bind.
Если вы беспокоитесь о производительности, вам лучше проверить, являются ли значения, которые вы собираетесь связать, нулевыми или нет, а затем выдать другой оператор SQL, чтобы избежать OR.
insert into account_type_standard
(account_type_Standard_id, tax_status_id, recipient_id)
(
select
account_type_standard_seq.nextval,
ts.tax_status_id,
r.recipient_id
from tax_status ts, recipient r
where (ts.tax_status_code = ? OR (ts.tax_status_code IS NULL and ? IS NULL))
and (r.recipient_code = ? OR (r.recipient_code IS NULL and ? IS NULL))
попробуй:
insert into account_type_standard (account_type_Standard_id, tax_status_id, recipient_id)
select account_type_standard_seq.nextval,
ts.tax_status_id,
( select r.recipient_id
from recipient r
where r.recipient_code = ?
)
from tax_status ts
where ts.tax_status_code = ?
insert into account_type_standard (account_type_Standard_id, tax_status_id, recipient_id)
select account_type_standard_seq.nextval,
ts.tax_status_id,
( select r.recipient_id
from recipient r
where r.recipient_code = ?
)
from tax_status ts
where ts.tax_status_code = ?
insert into received_messages(id, content, status)
values (RECEIVED_MESSAGES_SEQ.NEXT_VAL, empty_blob(), '');