在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
);
答案 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
为当前连接获取的最后一个值。因此,即使其他事务(这意味着不同的连接)在这两个语句之间调用nextval
,currval
仍会反映“此”nextval
调用的值。
引用序列的每个用户都可以访问他或她当前的序列号,这是会话中生成的最后一个序列。用户可以发出语句以生成新的序列号或使用会话最后生成的当前号码。在会话中的语句生成序列号后,它仅对此会话可用。
答案 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;