在oracle过程中如何获取刚刚添加的PKId作为下一个表的FK ID添加

时间:2015-10-07 11:29:38

标签: sql oracle plsql

在oracle过程中,我需要在EmployeeHeader表中插入数据,然后将此表的PK id作为EmployeeDetails表的FK id插入。我们怎样才能做到这一点?

 INSERT INTO EmployeeHeader(
              HEADER_PK_ID
                      empNo

         )
         VALUES(
                    HEADER_PK_ID_SEQ.NEXTVAL,
                    'SOMETHING'

              );

 INSERT INTO EmployeeDetails (
              DTLHEADER_PK_ID,
              HEADER_fK_ID
                      empname,
              age

         )
         VALUES(
                    DTLHEADER_PK_ID_SEQ.NEXTVAL,
                    HEADER_PK_IDn, -- (THIS NEEDS TO BE FETCHED FROM EmployeeHeader)
                    21
              );

5 个答案:

答案 0 :(得分:4)

在大多数情况下,您可以使用currval

select HEADER_PK_ID_SEQ.CURRVAL
from dual;

如果希望值对于并发插入是安全的,则可能需要将两个插入包装在单个事务中。

答案 1 :(得分:3)

使用INSERT语句的RETURNING子句:

DECLARE
  nHeader_pk_id  NUMBER;
BEGIN
  INSERT INTO EmployeeHeader
    (HEADER_PK_ID, EMPNO)
  VALUES
    (HEADER_PK_ID_SEQ.NEXTVAL, 'SOMETHING')
  RETURNING HEADER_PK_ID INTO nHeader_pk_id;

  INSERT INTO EmployeeDetails
    (DTLHEADER_PK_ID, HEADER_FK_ID, EMPNAME, AGE)
  VALUES
    (DTLHEADER_PK_ID_SEQ.NEXTVAL, nHeader_pk_id, 'Somebody', 21);
END;

我个人的偏好是使用ON INSERT触发器来处理主键字段的填充,方法如下:

CREATE OR REPLACE TRIGGER EMPLOYEEHEADER_BI
  BEFORE INSERT ON EMPLOYEEHEADER
  FOR EACH ROW
BEGIN
  IF :NEW.HEADER_PK_ID IS NULL THEN
    :NEW.HEADER_PK_ID := HEADER_PK_ID_SEQ.NEXTVAL;
  END IF;
END EMPLOYEEHEADER_BI;

CREATE OR REPLACE TRIGGER EMPLOYEEDETAILS_BI
  BEFORE INSERT ON EMPLOYEEDETAILS
  FOR EACH ROW
BEGIN
  IF :NEW.DTLHEADER_PK_ID IS NULL THEN
    :NEW.DTLHEADER_PK_ID := DTLHEADER_PK_ID_SEQ.NEXTVAL;
  END IF;
END EMPLOYEEDETAILS_BI;

并且INSERT语句变为:

DECLARE
  nHeader_pk_id     NUMBER;
  nDtlheader_pk_id  NUMBER;
BEGIN
  INSERT INTO EmployeeHeader
    (EMPNO)  -- Note: PK field not mentioned - will be populated by trigger
  VALUES
    ('SOMETHING')
  RETURNING HEADER_PK_ID INTO nHeader_pk_id;

  INSERT INTO EmployeeDetails
    (HEADER_FK_ID, EMPNAME, AGE)  -- Note: PK field not mentioned - will be populated by trigger
  VALUES
    (nHeader_pk_id, 'Somebody', 21)
  RETURNING DTLHEADER_PK_ID INTO nDtlheader_pk_id;
END;

(我使用IF pk_field IS NULL THEN构造,因为我经常需要将数据从生产数据库复制到开发数据库,​​并希望保留从生产中提取的任何键值以简化调试。如果没有此要求,可以删除IS NULL检查并直接将序列的NEXTVAL分配给列。

以这种方式完成应用程序代码不需要知道或关心使用哪个序列来生成特定表的主键值,并且主键字段总是最终填充。

祝你好运。

答案 2 :(得分:1)

您可以使用RETURNING子句。

以下是一个例子:

create sequence test_seq1
  start with 1
  maxvalue 999
  minvalue 1
  nocycle
  cache 20
  noorder;

create sequence test_seq2
  start with 100
  maxvalue 999
  minvalue 1
  nocycle
  cache 20
  noorder;

create table test_tab_p (col1 number, col2 number);

create table test_tab_c (col1 number, col2 number, col3 number);

declare
  v_p_col2 number := 1;
  v_c_col3 number := 10;

  v_p_col1 number;
begin
  insert into test_tab_p (col1, col2)
  values (test_seq1.nextval, v_p_col2)
  returning col1 into v_p_col1;

  insert into test_tab_c (col1, col2, col3)
  values (test_seq2.nextval, v_p_col1, v_c_col3);

  commit;
end;
/

select * from test_tab_p;

      COL1       COL2
---------- ----------
         1          1

select * from test_tab_c;

      COL1       COL2       COL3
---------- ---------- ----------
       100          1         10

答案 3 :(得分:1)

使用currval

INSERT INTO EmployeeHeader
  (header_pk_id, empNo)
VALUES
  (header_pk_id_seq.nextval, 'SOMETHING');

INSERT INTO EmployeeDetails 
  (dtlheader_pk_id, header_fk_id, empname, age)
VALUES
  (dtlheader_pk_id_seq.nextval, header_pk_id_seq.currval, 21);

currval在这里使用是安全的。它始终返回nextval 为当前连接获取的最后一个值。因此,即使其他事务(这意味着不同的连接)在这两个语句之间调用nextvalcurrval仍会反映“此”nextval调用的值。

Quote from the manual:

  

引用序列的每个用户都可以访问他或她当前的序列号,这是会话中生成的最后一个序列。用户可以发出语句以生成新的序列号或使用会话最后生成的当前号码。在会话中的语句生成序列号后,它仅对此会话可用。

答案 4 :(得分:1)

非常有效的方法是将seq id值保存到变量中,然后将其用于整个事务。以下是提到的例子。如有任何问题,请告诉我。

    DECLARE
      lv_pkid PLS_INTEGER:=SEQ.NEXTVAL;
    BEGIN
      INSERT
      INTO EmployeeHeader
        (
          HEADER_PK_ID,
          empNo
        )
        VALUES
        (
          lv_pkid,
          'SOMETHING'
        );
      INSERT
      INTO EmployeeDetails
        (
          DTLHEADER_PK_ID,
          HEADER_fK_ID,
          empname,
          age
        )
        VALUES
        (
          DTLHEADER_PK_ID_SEQ.NEXTVAL,
          lv_pkid, -- (THIS NEEDS TO BE FETCHED FROM EmployeeHeader)
          21
        );
COMMIT;
    END;