【问题标题】:Oracle Insert via Select from multiple tables where one table may not have a rowOracle 通过 Select 从多个表中插入,其中一个表可能没有一行
【发布时间】:2026-02-12 12:35:02
【问题描述】:

我有许多代码值表,其中包含一个代码和一个带有 Long 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_code 可以为空,因此 ?替换值可以为空。当然,隐式连接不会返回一行,因此不会将行插入到我的表中。

我试过在 ?在 r.recipient_id 上。

我试图在 r.recipient_code = 上强制进行外部联接?通过添加(+),但它不是显式连接,所以Oracle仍然没有添加另一行。

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

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

【问题讨论】:

    标签: sql oracle select insert


    【解决方案1】:

    在这种情况下,外部联接不会“按预期”工作,因为您已明确告诉 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,
    

    【讨论】:

    • 如果 tax_status 或接收者中有多个条目,如果接收者代码为 NULL 会怎样?
    • 刚试了一下,null 收件人代码导致 account_type_standard 上的 recipient_id 列为 null。不知道多个条目,但在我的情况下,表格有唯一的代码,所以我没问题。
    • 按照 Tony Andrews 的说法,序列值不需要 Select from DUAL。只能有 account_type_standard_seq.nextval。
    【解决方案2】:

    我不清楚 ts.tax_status_code 是主键还是备用键。与收件人代码相同。知道这一点会很有用。

    您可以使用 OR 来处理绑定变量为 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))
    

    【讨论】:

    • 这个查询不是很慢吗?
    • 是的,因此我关于“如果您担心性能......”的声明
    【解决方案3】:

    试试:

    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 的答案更有效吗?如果是这样,我可以动摇接受这个回应。否则,我认为将所有选择放在各自的位置比使用长 from 和 where 子句更清楚。我知道这就是我所拥有的,但是......
    • 我不认为它明显更好(或更糟)。但是,Oglester 的解决方案不需要从 DUAL 中选择 - 我发布了一个显示修改版本的新答案(只是稍微更有效)
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:
      insert into received_messages(id, content, status)
          values (RECEIVED_MESSAGES_SEQ.NEXT_VAL, empty_blob(), '');
      

      【讨论】:

        【解决方案6】:
        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 = ?
        

        【讨论】:

          最近更新 更多