2015-04-10 3 views
3

Я сконфигурировал базу данных firebird для автоматического инициализации первичного ключа таблицы.Firebird/IBPP: Как получить идентификатор, сгенерированный автоинкрементацией базы данных?

CREATE GENERATOR GEN_CHANNEL_PARAMETER_SET_ID; 
SET GENERATOR GEN_CHANNEL_PARAMETER_SET_ID TO 0; 

CREATE TRIGGER CHANNEL_PARAMETER_SETS_BI FOR CHANNEL_PARAMETER_SETS 
ACTIVE BEFORE INSERT POSITION 0 
AS 
BEGIN 
    if (NEW.CHANNEL_PARAMETER_SET_ID is NULL) then NEW.CHANNEL_PARAMETER_SET_ID = GEN_ID(GEN_CHANNEL_PARAMETER_SET_ID, 1); 
END 

Теперь в моем C++ программа, использующая ППИР У меня есть следующая проблема:

При установке набора данных в новую строку этой таблицы программы я знаю, все значения в моем C++ Зависит новый первичный ключ, потому что база данных создает его. Как я могу получить этот ключ из базы данных?

Возможно, кто-то еще вставил запись - через мгновение после того, как я вставил ее. Таким образом, получение PK с наивысшим значением может создать ошибку. Как я могу справиться с этим?


Принятие ответ Амир Рахими Farahani, я нашел следующее решение моей проблемы:

Я использую генератор:

CREATE GENERATOR GEN_CHANNEL_PARAMETER_SET_ID; 
SET GENERATOR GEN_CHANNEL_PARAMETER_SET_ID TO 0; 

и следующий C++/IBPP/SQL кода:

// SQL statement 
m_DbStatement->Execute(
    "SELECT NEXT VALUE FOR gen_channel_parameter_set_id FROM rdb$database" 
    ); 

// Retrieve Data 
IBPP::Row ibppRow; 
int64_t channelParameterSetId; 

m_DbStatement->Fetch(ibppRow); 
ibppRow->Get (1, channelParameterSetId); 


// SQL statement 
m_DbStatement->Prepare(
    "INSERT INTO channel_parameter_sets " 
    "(channel_parameter_set_id, ...) " 
    "VALUES (?, ...) " 
    );  

// Set variables 
m_DbStatement->Set (1, channelParameterSetId); 
... 
... 

// Execute 
m_DbStatement->Execute(); 
m_DbTransaction->CommitRetain(); 

ответ

4

Можно создавать и использовать новый идентификатор, прежде чем вставить новую запись:

SELECT NEXT VALUE FOR GEN_CHANNEL_PARAMETER_SET_ID FROM rdb$database 

Теперь вы знаете значение для нового первичного ключа.

Update:
ППИР поддерживает RETURNING тоже:

// SQL statement 
m_DbStatement->Prepare(
    "INSERT INTO channel_parameter_sets " 
    "(...) VALUES (...) RETURNING channel_parameter_set_id" 
    );  

// Execute 
m_DbStatement->Execute(); 
m_DbTransaction->CommitRetain(); 

// Get the generated id 
m_DbStatement->Get (1, channelParameterSetId); 
... 
+0

Это прямое решение. Но я думаю, что есть недостаток, который счетчик увеличивает каждый раз, когда оператор (SELECT NEXT VALUE FOR ...) выполняется, даже если вставка впоследствии терпит неудачу. Или есть способ справиться с этим? –

+2

Триггерный подход «ПЕРЕД ВСТРОЕНИЕМ» имеет тот же эффект, если после этого вставка выходит из строя. –

3

Чтобы получить значение сгенерированного ключа (или любого другого столбца), вы можете использовать INSERT ... RETURNING ....

Например:

INSERT INTO myTable (x, y, z) VALUES (1, 2, 3) RETURNING ID 

Также много водителей обеспечивают дополнительные возможности для поддержки RETURNING, но я не знаю ППИР.

Обратите внимание, что с точки зрения водителя использование RETURNING приведет к тому, что вставка будет действовать как исполняемая хранимая процедура; некоторые драйверы могут потребовать, чтобы вы выполнили его определенным образом.

+0

Должен ли я написать свою собственную хранимую процедуру, чтобы использовать RETURNING команду? –

+0

@Ergodicity Нет, вам не нужно это делать, однако запрос с функцией RETURNING обрабатывается firebird **, как если бы это была ** хранимая процедура, а для некоторых драйверов это означает, что вам нужно выполнить ее в определенном (так же, как вы выполняете «ВЫПОЛНЕННУЮ ПРОЦЕДУЮ»). –

+0

Я попытался: 'INSERT INTO channel_parameter_sets (parameter_set_id, channel_fk, parameter_id_fk, parameter_value) VALUES (1, 2, 14, 42) RETURNING channel_parameter_set_id'. Была добавлена ​​новая строка, но, к сожалению, значение не было возвращено. Поэтому я думаю, что я воспользуюсь решением Амира Рахими Фарахани. Даже ваш, кажется, более изящный. –

Смежные вопросы