web-dev-qa-db-ja.com

1つのテーブルに行がない可能性がある複数のテーブルからのSelect経由のOracle Insert

長いIDのコードと説明を含むコード値テーブルがいくつかあります。

いくつかのコードを参照するアカウントタイプのエントリを作成したいので、次のようにします。

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可能であるため、?置換値はnullになる可能性があります。もちろん、暗黙の結合は行を返さないため、行がテーブルに挿入されません。

私はNVLを使ってみましたか?およびr.recipient_idにあります。

R.recipient_code =?に外部結合を強制しようとしました(+)を追加しますが、明示的な結合ではないため、Oracleはまだ別の行を追加していません。

誰でもこれを行う方法を知っていますか?

ステートメントを変更して、recipient_idを外部で検索し、? r.recipient_idの代わりに、受信者テーブルから選択しないでください。ただし、これをすべて1つのSQLステートメントで実行することをお勧めします。

12
Mikezx6r

その場合、Outter結合は「期待どおりに」機能しません。そのテーブルの基準が一致する場合にのみデータが必要であるとOracleに明示的に指示したためです。そのシナリオでは、外部結合は役に立たなくなります。

回避策

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句に追加できますOR MAXやMINなどの集計を使用します。これはもちろん、すべてのケースに最適なソリューション。

[編集]コメントごと、

  (SELECT account_type_standard_seq.nextval FROM DUAL),

ちょうどすることができます

  account_type_standard_seq.nextval,
23
Greg Ogle

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 = ?)
)
7
Tony Andrews

試してください:

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 = ?
3
Tony Andrews

Ts.tax_status_codeが主キーまたは代替キーであるかどうかは、質問ではわかりませんでした。 recipient_codeについても同様です。これは知っておくと役に立ちます。

次のようにORを使用して、バインド変数がnullになる可能性に対処できます。同じことを最初の2つのバインド変数にバインドします。

パフォーマンスが心配な場合は、バインドする値がnullかどうかを確認し、ORを回避するために別のSQLステートメントを発行することをお勧めします。

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))
3
WW.
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 = ?
1
paparao