Home > other >  Conditionally insert into another table if id exists in another table else insert into both both tab
Conditionally insert into another table if id exists in another table else insert into both both tab

Time:10-03

If customer id exists in table A, insert order in table B. if customer id does not exist in table A, insert customer id in table A and then order in table B. I have been trying to achieve this with if/else and merge but keep running into invalid sql statement.

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;

CodePudding user response:

The IF THEN ELSE logic is not needed for this case. Instead make use of the database built-in functionality. customerid should be your primary key, so if you try to insert and it already exists that will raise the DUP_VAL_ON_INDEX exception.

Check the following example:

-- 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;  
/

run the above block a couple of times. Only the first time it will insert a customer.

CodePudding user response:

Suppose you have 2 very simple tables.

Tables

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

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

An anonymous block, containing IF .. ELSE .. END IF and EXISTS() similar to the code in your question, causes an error:

function or pseudo-column 'EXISTS' may be used inside a SQL statement only

    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

One solution may be to do the following (see 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  

After the first execution of the anonymous block, the tables contain the following rows:

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

Execute the anonymous block again, and you get ...

1 rows affected

dbms_output:
if

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

DBfiddle here.

CodePudding user response:

You may use multitable insert and use the fact that aggregate function without group by always returns a row with null in case of absent (= not satisfying where condition) row.

The code is below:

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

1 rows affected

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 rows affected

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 rows affected

You may also use two inserts with documented ignore_row_on_dupkey_index hint, which does what its name implies.

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 rows affected

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

db<>fiddle here

  • Related