通过从多个表中选择进行Oracle插入,其中一个表可能没有行

时间:2020-03-06 14:42:05  来源:igfitidea点击:

我有许多代码值表,其中包含一个代码和一个带有长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和收件人表中检索适当的值。不幸的是,receiver_code是可为空的,因此?替换值可以为null。当然,隐式联接不会返回任何行,因此不会将行插入到我的表中。

我尝试在上使用NVL?并在r.recipient_id上。

我试图在r.recipient_code =上强制进行外部联接。通过添加(+),但它不是显式联接,因此Oracle仍未添加另一行。

有人知道这样做的方法吗?

我显然可以修改该语句,以便在外部进行receive_id的查找,并带有??而不是r.recipient_id,并且根本不从收件人表中进行选择,但是我更愿意在1条SQL语句中完成所有这些操作。

解决方案

在这种情况下,外部联接无法"按预期的方式工作",因为我们已明确告知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子句中,或者使用汇总(例如MAX或者MIN)。当然,这可能不是所有情况下的最佳解决方案。

[编辑]每条评论,

(SELECT account_type_standard_seq.nextval FROM DUAL),

可以只是

account_type_standard_seq.nextval,

对于ts​​.tax_status_code是主键还是备用键,这个问题对我来说还不清楚。与收件人代码相同。知道这一点将很有用。

我们可以使用OR来解决绑定变量为null的可能性,如下所示。我们将把相同的东西绑定到前两个绑定变量。

如果我们担心性能,最好检查要绑定的值是否为null,然后发出不同的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 = ?

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

insert into received_messages(id, content, status)
    values (RECEIVED_MESSAGES_SEQ.NEXT_VAL, empty_blob(), '');