Вставка значений в таблицы с помощью внешнего ключа

#sql #firebird #firebird-3.0

#sql #firebird #firebird-3.0

Вопрос:

Я хочу вставить некоторые значения в две таблицы в цикле, но, похоже, я не могу этого сделать из-за внешнего ключа. Однако тот же код работает в 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,@i,RAND()*(10000) ),
( null,@i,RAND()*(10000) ),
( null,@i,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), MOD(RAND(),1000) FROM RDB$DATABASE UNION ALL
        select (:cnt2), MOD(RAND(),1000) FROM RDB$DATABASE UNION ALL
        select (:cnt2), MOD(RAND(),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:WINDOWSSYSTEM32firebird.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)
);
 

Как мне это исправить?

Ответ №1:

Ваш код Firebird не эквивалентен вашему коду SQL Server. Ваш код SQL Server начинается с 1 , а ваш код Firebird начинается с 0 . Первое значение, сгенерированное для столбца идентификатора 1 , равно not 0 , поэтому ваша вставка не соответствует ограничению внешнего ключа, поскольку в with нет записи DOKUMENTY ID_DOKUMENTU = 0 . Итак, немедленное решение — использовать declare variable cnt2 integer = 1; вместо declare variable cnt2 integer = 0;

Однако в настоящее время ваш код полагается на столбец identity, который фактически начинается с определенного значения ( 1 ) и всегда увеличивается на 1. Это небезопасное решение, например, если вы попытаетесь запустить его сейчас с этим изменением, произойдет сбой, потому что вставка записи с ID_DOKUMENTU = 1 была отменена при сбое вашего блока выполнения, и следующая вставленная запись будет иметь более высокий идентификатор.

Вместо этого измените свой код, чтобы использовать фактический сгенерированный идентификатор:

 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), MOD(RAND(),1000) FROM RDB$DATABASE UNION ALL
        select (:ID_DOKUMENTU), MOD(RAND(),1000) FROM RDB$DATABASE UNION ALL
        select (:ID_DOKUMENTU), MOD(RAND(),1000) FROM RDB$DATABASE ;
        cnt2 = cnt2   1;
    end
end
 

Кроме того, MOD(RAND(),1000) не выполняет то же самое, RAND()*(10000) что и в вашем коде SQL Server.