【问题标题】:Conditionally insert into another table if id exists in another table else insert into both both tables in oracle如果 id 存在于另一个表中,则有条件地插入另一个表,否则插入到 oracle 中的两个表中
【发布时间】:2021-11-23 12:20:35
【问题描述】:

如果A表中存在客户ID,则在B表中插入订单。 如果表 A 中不存在客户 ID,则将客户 ID 插入表 A 中,然后在表 B 中订购。 我一直在尝试使用 if/else 和 merge 来实现这一点,但一直遇到 无效的 sql 语句

IF EXISTS (SELECT CustomerID FROM Customer_T WHERE CustomerID = 18)
    Insert into Order_T
    values(79,18,to_date('09/28/2021','mm/dd/yyyy'),to_date('10/01/2021','mm/dd/yyyy'),1,3)
ELSE
  insert INTO Customer_T VALUES (18,'Capitol Industries Ltd', '999 Fifth Avenue', 'New York', 'NY','10015')
  insert into Order_T values (79,18,to_date('09/28/2021','mm/dd/yyyy'),to_date('10/01/2021','mm/dd/yyyy'),1,3)
END IF;

【问题讨论】:

  • 我认为你需要在每条语句后加一个分号。插入是语句和 if-else-end if;是一种说法。所以,只要放 ;在每次插入之后。
  • 那也没用。同样的错误
  • 这个要求看起来很奇怪,因为如果你已经有一些 id,那么它应该来自某个东西。但是customer表中怎么能没有呢?
  • 所以基本上客户必须存在才能创建订单。因此,它检查客户是否存在,对客户表不做任何事情,而是使用该客户 ID 创建一个新订单。但如果客户不存在,首先创建一个新客户,然后使用该客户 ID 创建一个新订单

标签: sql oracle oracle-apex


【解决方案1】:

假设您有 2 个非常简单的表格。

表格

create table T1( num_ )
as
select 1 from dual ;

create table T2( num_ )
as
select 200 from dual ;

与您问题中的代码类似,包含 IF .. ELSE .. END IF 和 EXISTS() 的匿名块会导致错误:

函数或伪列 'EXISTS' 可以在 SQL 语句中使用 只有

    begin
      if exists( select num_ from T1 where num_  = 2 ) then
        insert into T2( num_ ) values( 2 ) ;
        dbms_output.put_line( 'if' ) ;
      else
        insert into T1( num_ ) values( 2 ) ;
        insert into T2( num_ ) values( 2 ) ;
        dbms_output.put_line( 'else' ) ;
      end if ;
    end ;
    /
-- error:
... function or pseudo-column 'EXISTS' may be used inside a SQL statement only

一种解决方案可能是执行以下操作(请参阅 asktom.oracle.com - Equivalent for EXISTS() in an IF statement

begin
  for x in ( select count(*) cnt
             from dual
             where exists ( select num_ from T1 where num_  = 2  ) 
  ) loop
    if ( x.cnt = 1 ) then                  -- found
      insert into T2( num_ ) values( 2 ) ;
      dbms_output.put_line( 'if' ) ;
    else                                   -- not found
      insert into T1( num_ ) values( 2 ) ;
      insert into T2( num_ ) values( 2 ) ;
      dbms_output.put_line( 'else' ) ; 
    end if;
  end loop;
end;
/

-- output:
1 rows affected

dbms_output:
else  

第一次执行匿名块后,表包含以下行:

select num_, '<- T1' as table_ from T1
union all
select num_, '<- T2' from T2 ;

-- result
NUM_    TABLE_
1       <- T1
2       <- T1
200     <- T2
2       <- T2

再次执行匿名块,你得到...

1 rows affected

dbms_output:
if

-- tables
NUM_    TABLE_
1       <- T1
2       <- T1
200     <- T2
2       <- T2
2       <- T2

DBfiddle here.

【讨论】:

    【解决方案2】:

    这种情况不需要IF THEN ELSE 逻辑。而是使用数据库内置功能。 customerid 应该是您的主键,因此如果您尝试插入并且它已经存在,则会引发 DUP_VAL_ON_INDEX 异常。

    检查以下示例:

    -- create tables
    create table customers (
        id                             number generated by default on null as identity 
                                       constraint customers_id_pk primary key,
        name                           varchar2(255 char)
    )
    ;
    
    create table orders (
        id                             number generated by default on null as identity 
                                       constraint orders_id_pk primary key,
        customer_id                    number
                                       constraint orders_customer_id_fk
                                       references customers on delete cascade,
        product                        varchar2(100 char)
    )
    ;
    
    BEGIN
      BEGIN
        insert INTO customers VALUES (2,'Capitol Industries Ltd');
      EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
        NULL; 
      END;
      insert into orders (customer_id,product) values (2,'a book');
    END;  
    /
    

    运行上述代码块几次。只有第一次才会插入客户。

    【讨论】:

      【解决方案3】:

      您可以使用multitable insert 并使用这样一个事实,即没有group by 的聚合函数在不存在(= 不满足where 条件)行的情况下总是返回带有null 的行。

      代码如下:

      insert into customers(id, name, company, state)
      values (1, 'Some name', 'Some company', 'NY')
      

      1 行受影响

      insert all
        when cust_exists = 0
        then
          into customers (id, name, company, state)
          values (cust_id, cust_name, company, state)
      
        when 1 = 1
        then
          into orders (id, customer_id, order_date, due_date, some_id)
          values(order_id, cust_id, order_date, due_date, some_id)
      select
        1 as order_id,
        1 as cust_id,
        'Some other name' as cust_name,
        'Company' as company,
        'NY' as state,
        date '2021-09-28' as order_date,
        date '2021-10-03' as due_date,
        100 as some_id,
        nvl(max(1), 0) as cust_exists
      from customers
      where id = 1
      

      1 行受影响

      insert all
        when cust_exists = 0
        then
          into customers (id, name, company, state)
          values (cust_id, cust_name, company, state)
      
        when 1 = 1
        then
          into orders (id, customer_id, order_date, due_date, some_id)
          values(order_id, cust_id, order_date, due_date, some_id)
      select
        2 as order_id,
        2 as cust_id,
        'Some other name' as cust_name,
        'Company' as company,
        'NY' as state,
        date '2021-09-28' as order_date,
        date '2021-10-03' as due_date,
        100 as some_id,
        nvl(max(1), 0) as cust_exists
      from customers
      where id = 2
      

      2 行受影响

      您还可以使用两个带有 documented ignore_row_on_dupkey_index 提示的插入,正如其名称所暗示的那样。

      insert /*+
        ignore_row_on_dupkey_index(customers(id))
      */
      into customers (id, name, company, state)
      values (2, 'Name', 'Comp', 'NY')
      

      insert into orders (id, customer_id, order_date, due_date, some_id)
      values (3, 2, date '2021-09-30', date '2021-10-07', 5)
      

      1 行受影响

      select *
      from customers
      
      ID NAME COMPANY STATE
      1 Some name Some company NY
      2 Some other name Company NY

      db小提琴here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-17
        • 1970-01-01
        • 2016-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多