【问题标题】:How to insert long-format data into two separate tables using SQL?如何使用 SQL 将长格式数据插入两个单独的表中?
【发布时间】:2021-06-22 04:02:09
【问题描述】:

我选择了以下要插入数据库的数据。

Letter Value
A 1
A 2
B 3
B 4

由于这种格式有“A”和“B”的重复,我想将数据拆分成两个单独的表:table1和table2。

表 1:

ID Letter
1 A
2 B

此处的 ID 由数据库自动插入(使用序列)。

表2:

table1_id Value
1 1
1 2
2 3
2 4

在这个特定的示例中,我没有在存储方面获得任何收益,但它以最好的方式说明了我遇到的问题。

如何使用 SQL 或 PL/SQL 向 table1 和 table2 插入数据?

【问题讨论】:

    标签: sql oracle plsql


    【解决方案1】:

    首先从源中填充 table1

    insert table1(Letter)
    select distinct Letter
    from srcTable;
    

    然后从源解码字母加载数据到id

    insert table2(table1_id, Value)
    select t1.id, src.value
    from srcTable src
    join table1 t1 on t1.Letter = src.Letter;
    

    【讨论】:

      【解决方案2】:

      您可以使用多表插入和解决方法来获得稳定的nextval 序列。由于nextval 在每一行上都被评估,而不管when 条件如何,在values 中使用它是不够的。

      insert all
        when rn = 1 then into l(id, val) values(seq, letter)
        when rn > 0 then into t(l_id, val) values(seq, val)
      
      with a(letter, val) as (
        select 'A', 1 from dual union all
        select 'A', 2 from dual union all
        select 'B', 3 from dual union all
        select 'B', 4 from dual union all
        select 'C', 5 from dual
      )
      , b as (
        select
          a.*,
          l.id as l_id,
          row_number() over(partition by a.letter order by a.val asc) as rn
        from a
          left join l
            on a.letter = l.val
      )
      
      select
        b.*,
        max(decode(rn, 1, coalesce(
              l_id,
              extractvalue(
                /*Hide the reference to the sequence due to restrictions
                of multitalbe insert*/
                dbms_xmlgen.getxmltype('select l_sq.nextval as seq from dual')
                , '/ROWSET/ROW/SEQ/text()'
              ) + 0
            ))
        ) over(partition by b.letter) as seq
      from b
      
      select *
      from l
      
      身份证 |价值 -: | :-- 1 |一个 2 |乙 3 | C
      select *
      from t
      
      L_ID |价值 ---: | --: 1 | 1 1 | 2 2 | 3 2 | 4 3 | 5

      db小提琴here

      【讨论】:

        【解决方案3】:

        主要是您需要生成table1 的ID 值以插入table2。为此,您可以在创建包含一些约束的表后使用 INSERT ... RETURNING ID INTO v_id 语句,尤其是独特的约束,例如 PRIMARY KEYUNIQUE

        CREATE TABLE table1( ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, letter VARCHAR2(1) NOT NULL );
        ALTER TABLE table1 ADD CONSTRAINT uk_tab1_letter UNIQUE(letter);
        CREATE TABLE table2( ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, table1_id INT, value INT );
        ALTER TABLE table2 ADD CONSTRAINT fk_tab2_tab1_id FOREIGN KEY(table1_id) REFERENCES table1 (ID);
        

        并添加异常处理,以免在第一个表中插入重复的字母。然后使用下面的代码块;

        DECLARE
          v_id     table1.id%TYPE;
          v_letter table1.letter%TYPE := 'A';
          v_value  table2.value%TYPE := 1;
        BEGIN
          BEGIN
            INSERT INTO table1(letter) VALUES(v_letter) RETURNING ID INTO v_id;
           EXCEPTION WHEN OTHERS THEN NULL;
          END;
          
          INSERT INTO table2(table1_id,value) SELECT id,v_value FROM table1 WHERE letter = v_letter;
          COMMIT;
        END;  
        /
        

        并通过将v_letter&v_value 的初始化值分别更改为'A'&2'B'&1'B'&2 ..等来运行。

        或者,您可以将代码块转换为存储过程或函数,例如

        CREATE OR REPLACE PROCEDURE Pr_Ins_Tabs( 
                                                 v_letter table1.letter%TYPE, 
                                                 v_value  table2.value%TYPE 
                                               ) AS
          v_id     table1.id%TYPE;
        BEGIN
          BEGIN
            INSERT INTO table1(letter) VALUES(v_letter) RETURNING ID INTO v_id;
           EXCEPTION WHEN OTHERS THEN NULL;
          END;
          
          INSERT INTO table2(table1_id,value) SELECT id,v_value FROM table1 WHERE letter = v_letter;
          COMMIT;
        END;  
        /
        

        为了有弹性地撤销如

        BEGIN
         Pr_Ins_Tabs('A',2);
        END;
        /
        

        Demo

        附言。 如果您的数据库版本早于 12c,则创建序列(seq1&seq2)并在插入语句中使用seq1.nextval&seq2.nextval,因为在表创建中无法使用GENERATED ALWAYS AS IDENTITY 子句DDL 语句。

        【讨论】:

          猜你喜欢
          • 2023-03-04
          • 1970-01-01
          • 1970-01-01
          • 2013-12-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-23
          • 1970-01-01
          相关资源
          最近更新 更多