使用外键将值插入到表中

问题描述

我想在一个循环中的两个表中插入一些值,但由于外键,我似乎无法做到。但是,相同的代码sql Server 中确实有效。

这在 sql Server 中完美运行:

declare @i int = 1

while @i<1200
BEGIN

INSERT INTO DOKUMENTY VALUES(null,null);
INSERT INTO POZYCJE VALUES
( null,@i,RAND()*(10000) ),( null,RAND()*(10000) )

SET @i+=1

END

我正在尝试在 Firebird 中做同样的事情:

SET TERM #;
execute block 
as
declare variable cnt2 integer = 0;
begin
    while (cnt2 < 1200) do
    begin
        insert into DOKUMENTY(DATA_KSIEGOWANIA) values(current_date);

        insert INTO POZYCJE(ID_DOKUMENTU,KWOTA)
        select (:cnt2),MOD(RAND(),1000) FROM RDB$DATABASE UNION ALL
        select (:cnt2),1000) FROM RDB$DATABASE ;
        cnt2 = cnt2 + 1;
    end
end#

SET TERM;#

但是,我收到此错误

Error: *** IBPP::sqlException ***
Message: isc_dsql_execute2 Failed

sql Message : -530
can't format message 13:470 -- message file C:\WINDOWS\SYstem32\firebird.msg not found

Engine Code    : 335544466
Engine Message :
violation of FOREIGN KEY constraint "INTEG_44" on table "POZYCJE"
Foreign key reference target does not exist
Problematic key value is ("ID_DOKUMENTU" = 0)
At block line: 10,col: 9

这就是我创建表格的方式:

CREATE TABLE DOKUMENTY(
ID_DOKUMENTU integer generated by default as identity primary key,DATA_KSIEGOWANIA DATE
);

CREATE TABLE POZYCJE(
ID_POZYCJI integer generated by default as identity primary key,ID_DOKUMENTU integer,FOREIGN KEY(ID_DOKUMENTU) references DOKUMENTY(ID_DOKUMENTU),KWOTA decimal(18,2)
);

我该如何解决这个问题?

解决方法

您的 Firebird 代码不等同于您的 SQL Server 代码。您的 SQL Server 代码从 1 开始,而 Firebird 代码从 0 开始。为标识列生成的第一个值是 1,而不是 0,因此您的插入失败了外键约束,因为 DOKUMENTY 中没有包含 ID_DOKUMENTU = 0 的记录。因此,直接的解决方案是使用 declare variable cnt2 integer = 1; 而不是 declare variable cnt2 integer = 0;

但是,您的代码目前依赖于实际从特定值 (1) 开始的标识列,并且始终以 1 递增。这不是一个安全的解决方案,例如,如果您尝试运行它现在有了这个更改,它会失败,因为当您的执行块失败时,带有 ID_DOKUMENTU = 1 的记录的插入已被撤消,并且插入的下一条记录将具有更高的 id。

相反,修改您的代码以使用实际生成的 ID:

execute block 
as
declare variable cnt2 integer = 1;
declare variable ID_DOKUMENTU type of column DOKUMENTY.ID_DOKUMENTU;
begin
    while (cnt2 < 1200) do
    begin
        insert into DOKUMENTY(DATA_KSIEGOWANIA) values(current_date) 
           returning ID_DOKUMENTU into ID_DOKUMENTU;

        insert INTO POZYCJE(ID_DOKUMENTU,KWOTA)
        select (:ID_DOKUMENTU),MOD(RAND(),1000) FROM RDB$DATABASE UNION ALL
        select (:ID_DOKUMENTU),1000) FROM RDB$DATABASE ;
        cnt2 = cnt2 + 1;
    end
end

顺便说一句,MOD(RAND(),1000) 与 SQL Server 代码中的 RAND()*(10000) 做的事情不同。