【问题标题】:How to insert values into table based on existing rows in table如何根据表中的现有行向表中插入值
【发布时间】:2018-10-17 01:37:12
【问题描述】:

我有一个表 inv_dtl,其中一个序列作为主键。 我需要一个插入语句来按照以下要求插入值:

  1. 如果表中已经存在该行(不包括主键值),我需要插入值为“I”的最后一列(status_flag)的值。

  2. 如果不存在,我需要插入 status_flag 列值为“A”的值。

【问题讨论】:

  • 存在于表中(不包括主键值)是什么意思?
  • @maxim - 我的意思是如果我插入的行已经存在于表中。主键值不会已经存在,因为我正在使用它的序列。
  • 所以如果表中有一行的所有列都等于您要插入的值,则存在行。正确的?在这种情况下,您留下一行状态为 A 并插入新行状态为 I?
  • 是的。如果存在,我必须将列值插入为“I”,如果不存在,我必须将其插入为“A”。所有其他列值将按原样插入。
  • 一步一步发布了另一个答案,看看对你有用。

标签: sql oracle


【解决方案1】:

据我了解,您正在使用某种语言来处理数据库。

有两种方式:

  1. 首先检查一条记录是否已经存在:select 1 from inv_dtl where col1 = val1 and col2 = val2 etc。然后插入具有不同标志的新记录。您在您的语言的源代码中决定哪个标志。
  2. 使用棘手的sql语句:insert into inv_dtl(col1, col2, etc.) values(val1, val2, etc., case (select 'X' from inv_dtl where col1 = val1 and col2 = val2, etc.) when 'X' then 'I' else 'A' end)

【讨论】:

    【解决方案2】:

    假设表“inv_dtl”包含字段(“ID”、“status_flag”)。还有一个名为“inv_dtl_seq”的序列。

    首先,您必须创建如下函数

    CREATE OR REPLACE FUNCTION inv_dtl_seq_fnc
     RETURN NUMBER
    IS
      v_seq_val  NUMBER;
    BEGIN
      EXECUTE IMMEDIATE 'select inv_dtl_seq.nextval from dual'
         INTO v_seq_val;
    
      RETURN v_seq_val;
    END inv_dtl_seq_fnc;
    

    现在,试试下面的 SQL 块,对你有用。

    merge into inv_dtl i
    using (select inv_dtl_seq_fnc new_id from dual) d
      on (i.id = d.new_id)
    when matched then 
      update set status = 'I'
    when not matched then
    insert values(d.new_id,'A');
    

    【讨论】:

    • 谢谢。但是我不能在这里使用 pl/sql,因为一旦从前端单击一个按钮,就会发生插入。
    • 查看我的更新答案。在这里你必须先创建一个函数。然后您可以使用合并语句进行比较,然后根据 ID 的匹配进行更新/插入。
    • 据我了解,在这两种情况下都必须插入新记录。
    • 是的,如果新 ID 已经存在,那么它会将状态更新为“I”,否则它将插入新记录。
    • 是的,格言做对了。我需要在这两种情况下插入。根本没有更新。
    【解决方案3】:

    从问题看来,对于所有匹配记录,status_flag 将为“A”的记录似乎只有一行,假设这一点,您可以在新值上使用左外连接编写查询,然后使用case 语句来识别 status_code 的值。

    INSERT INTO inv_dtl
    SELECT a.p_id,
           a.col1,
           a.col2,
           CASE WHEN b.status_flag IS NULL THEN 'A' ELSE 'I' END AS status_flag
      FROM (SELECT 1 p_id, -- new values goes here
                   100 col1,
                   'new 2' col2,
                   'A' status_flag
              FROM dual) a
      LEFT OUTER JOIN (SELECT * FROM inv_dtl) b
        ON b.col1 = a.col1 -- all columns list goes here
       AND b.col2 = a.col2
       AND b.status_flag = 'A'; -- Status 'A' is fixed.
    

    测试代码:

    SQL> create table inv_dtl(p_key number, col1 number, col2 varchar2(10), status_flag varchar2(1));
    Table created
    
    SQL> INSERT INTO inv_dtl
      2  SELECT a.p_id,
      3         a.col1,
      4         a.col2,
      5         CASE WHEN b.status_flag IS NULL THEN 'A' ELSE 'I' END AS status_flag
      6    FROM (SELECT 1 p_id,
      7                 100 col1,
      8                 'new' col2,
      9                 'A' status_flag
     10            FROM dual) a
     11    LEFT OUTER JOIN (SELECT * FROM inv_dtl) b
     12      ON b.col1 = a.col1
     13     AND b.col2 = a.col2
     14     AND b.status_flag = 'A';
    1 row inserted
    
    SQL> 
    SQL> INSERT INTO inv_dtl
      2  SELECT a.p_id,
      3         a.col1,
      4         a.col2,
      5         CASE WHEN b.status_flag IS NULL THEN 'A' ELSE 'I' END AS status_flag
      6    FROM (SELECT 2 p_id,
      7                 100 col1,
      8                 'new' col2,
      9                 'A' status_flag
     10            FROM dual) a
     11    LEFT OUTER JOIN (SELECT * FROM inv_dtl) b
     12      ON b.col1 = a.col1
     13     AND b.col2 = a.col2
     14     AND b.status_flag = 'A';
    1 row inserted
    
    SQL> 
    SQL> INSERT INTO inv_dtl
      2  SELECT a.p_id,
      3         a.col1,
      4         a.col2,
      5         CASE WHEN b.status_flag IS NULL THEN 'A' ELSE 'I' END AS status_flag
      6    FROM (SELECT 3 p_id,
      7                 100 col1,
      8                 'new' col2,
      9                 'A' status_flag
     10            FROM dual) a
     11    LEFT OUTER JOIN (SELECT * FROM inv_dtl) b
     12      ON b.col1 = a.col1
     13     AND b.col2 = a.col2
     14     AND b.status_flag = 'A';
    1 row inserted
    
    SQL> 
    SQL> INSERT INTO inv_dtl
      2  SELECT a.p_id,
      3         a.col1,
      4         a.col2,
      5         CASE WHEN b.status_flag IS NULL THEN 'A' ELSE 'I' END AS status_flag
      6    FROM (SELECT 4 p_id,
      7                 200 col1,
      8                 'new 2' col2,
      9                 'A' status_flag
     10            FROM dual) a
     11    LEFT OUTER JOIN (SELECT * FROM inv_dtl) b
     12      ON b.col1 = a.col1
     13     AND b.col2 = a.col2
     14     AND b.status_flag = 'A';
    1 row inserted
    
    SQL> 
    SQL> INSERT INTO inv_dtl
      2  SELECT a.p_id,
      3         a.col1,
      4         a.col2,
      5         CASE WHEN b.status_flag IS NULL THEN 'A' ELSE 'I' END AS status_flag
      6    FROM (SELECT 5 p_id,
      7                 200 col1,
      8                 'new 2' col2,
      9                 'A' status_flag
     10            FROM dual) a
     11    LEFT OUTER JOIN (SELECT * FROM inv_dtl) b
     12      ON b.col1 = a.col1
     13     AND b.col2 = a.col2
     14     AND b.status_flag = 'A';
    1 row inserted
    
    SQL> select * from inv_dtl;
         P_KEY       COL1 COL2       STATUS_FLAG
    ---------- ---------- ---------- -----------
             1        100 new        A
             2        100 new        I
             3        100 new        I
             4        200 new 2      A
             5        200 new 2      I
    
    SQL> 
    

    【讨论】:

    • 认为可以将 LEFT OUTER JOIN (SELECT * FROM inv_dtl) b 替换为 LEFT OUTER JOIN inv_dtl b
    • 也不要选择 'A' status_flag FROM dual
    • 这是为了提供灵活性,如果您想从 inv_dtl 表中过滤更多记录并且使用“A”状态标志,并且如果用户希望状态标志作为输入,可以用任何其他值替换,只需修改case语句。如果不需要,用户可以删除它们。
    【解决方案4】:

    这里是一步一步,你的解决方案。结帐可能对您有用。

    创建函数:

    CREATE OR REPLACE FUNCTION inv_dtl_seq_fnc(p1 number)
     RETURN NUMBER
    IS
      v_seq_val  NUMBER;
    BEGIN
    if p1 = 0 then
      EXECUTE IMMEDIATE 'select inv_dtl_seq.nextval from dual'
         INTO v_seq_val;
    elsif p1=1 then
      EXECUTE IMMEDIATE 'select inv_dtl_seq.currval from dual'
         INTO v_seq_val;
    end if;
    
      RETURN v_seq_val;
    END inv_dtl_seq_fnc;
    

    实际用例:

    create table inv_dtl(id number, status varchar2(200));
    create sequence inv_dtl_seq
         start with 1
         increment by 1 
         nocache 
         nocycle;
    
    
    insert into inv_dtl values(1,'A');
    select * from inv_dtl;
    
    ID  STATUS
    1   A
    
    insert into inv_dtl(id,status) 
      values (inv_dtl_seq_fnc(0),case when (select count(1) from inv_dtl where id = inv_dtl_seq_fnc(1)) > 0 then 'I' else 'A' end);
    
    select * from inv_dtl;
    ID  STATUS
    1   A
    1   I
    
    insert into inv_dtl(id,status) 
      values (inv_dtl_seq_fnc(0),case when (select count(1) from inv_dtl where id = inv_dtl_seq_fnc(1)) > 0 then 'I' else 'A' end);
    
    ID  STATUS
    1   A
    1   I
    2   A
    

    【讨论】:

      猜你喜欢
      • 2013-12-03
      • 2021-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多