Вопрос по IBX
Модератор: Модераторы
Вопрос по IBX
Подскажите, как модифицировать (добавлять) новые данные в таблицу через TIBDataSet (связан через DataSource с DBGrid), если он состоит из нескольких связанных таблиц. Как должен выглядеть UpdateSQL?
- *Rik*
- постоялец
- Сообщения: 453
- Зарегистрирован: 19.04.2011 12:18:51
- Откуда: Урал
- Контактная информация:
Mikhail писал(а):Подскажите, как модифицировать (добавлять) новые данные в таблицу через TIBDataSet (связан через DataSource с DBGrid), если он состоит из нескольких связанных таблиц. Как должен выглядеть UpdateSQL?
Код: Выделить всё
UPDATE MYTABLE SET
FIELD1 = :PARAM1,
FIELD2 = :PARAM2,
--и так далее
FIELDN = :PARAMN
WHERE MATABLE_ID = :PARAM_ID*Rik* писал(а):Mikhail писал(а):Подскажите, как модифицировать (добавлять) новые данные в таблицу через TIBDataSet (связан через DataSource с DBGrid), если он состоит из нескольких связанных таблиц. Как должен выглядеть UpdateSQL?Код: Выделить всё
UPDATE MYTABLE SET
FIELD1 = :PARAM1,
FIELD2 = :PARAM2,
--и так далее
FIELDN = :PARAMN
WHERE MATABLE_ID = :PARAM_ID
Это понятно, а если Dataset это две таблицы связанные через внешний ключ, т.е SelectSQL такой
Код: Выделить всё
SELECT F1, F2, F3
FROM Table1, Table2
WHERE Table2.FK_TABLE1 = TABLE1.PK_TABLE1;
Изменения вносятся в обе таблицы одновременно.
- Снег Север
- долгожитель
- Сообщения: 3067
- Зарегистрирован: 27.11.2007 15:14:47
- Контактная информация:
Аналогично:
Код: Выделить всё
UPDATE Table1, Table2
SET F1=:PARAM_F1, F2=:PARAM_F2, F3=:PARAM_F3
WHERE Table2.FK_TABLE1 = TABLE1.PK_TABLE1 AND Table2.FK_TABLE1= :PARAM_ID Снег Север писал(а):Аналогично:Код: Выделить всё
UPDATE Table1, Table2
SET F1=:PARAM_F1, F2=:PARAM_F2, F3=:PARAM_F3
WHERE Table2.FK_TABLE1 = TABLE1.PK_TABLE1 AND Table2.FK_TABLE1= :PARAM_ID
В операторе Update можно использовать только одну таблицу.
- *Rik*
- постоялец
- Сообщения: 453
- Зарегистрирован: 19.04.2011 12:18:51
- Откуда: Урал
- Контактная информация:
Mikhail писал(а):Это понятно, а если Dataset это две таблицы связанные через внешний ключ, т.е SelectSQL такой
Сделайте хранимую процедуру для модификации и можете через неё обновлять хоть 10 таблиц одновременно.
(или EXECUTE BLOCK)
В UpdateSQL будет
Код: Выделить всё
EXECUTE PROCEDURE MYPROC(:PARAM1, :PARAM2, :PARAM3)- Снег Север
- долгожитель
- Сообщения: 3067
- Зарегистрирован: 27.11.2007 15:14:47
- Контактная информация:
Mikhail писал(а):В операторе Update можно использовать только одну таблицу.
Ну извините, не знал что там так плохо, в MySQL я такую конструкцию использую постоянно...
*Rik* писал(а):Mikhail писал(а):Это понятно, а если Dataset это две таблицы связанные через внешний ключ, т.е SelectSQL такой
Сделайте хранимую процедуру для модификации и можете через неё обновлять хоть 10 таблиц одновременно.
(или EXECUTE BLOCK)
В UpdateSQL будетКод: Выделить всё
EXECUTE PROCEDURE MYPROC(:PARAM1, :PARAM2, :PARAM3)
А если все-таки это сделать это на клиенте? Как это обычно делается? На DBGrid такое просто так не получится сделать?
Т.е. форма, датасеты по числу участвующих таблиц, изменение их всех в рамках одной транзакции? Так что-ли?
- *Rik*
- постоялец
- Сообщения: 453
- Зарегистрирован: 19.04.2011 12:18:51
- Откуда: Урал
- Контактная информация:
Mikhail писал(а):А если все-таки это сделать это на клиенте? Как это обычно делается? На DBGrid такое просто так не получится сделать?
Т.е. форма, датасеты по числу участвующих таблиц, изменение их всех в рамках одной транзакции? Так что-ли?
Можно и так, если в одном запросе надо - то EXECUTE BLOCK, по другому ни как.
*Rik* писал(а):Mikhail писал(а):А если все-таки это сделать это на клиенте? Как это обычно делается? На DBGrid такое просто так не получится сделать?
Т.е. форма, датасеты по числу участвующих таблиц, изменение их всех в рамках одной транзакции? Так что-ли?
Можно и так, если в одном запросе надо - то EXECUTE BLOCK, по другому ни как.
Можно пример с EXECUTE BLOCK, а то что то не получается
- *Rik*
- постоялец
- Сообщения: 453
- Зарегистрирован: 19.04.2011 12:18:51
- Откуда: Урал
- Контактная информация:
Mikhail писал(а):Можно пример с EXECUTE BLOCK, а то что то не получается
Только у меня из InsertSQL:
Код: Выделить всё
EXECUTE BLOCK(
CLIENT_ID BIGINT = :CLIENT_ID,
FAM VARCHAR(30) = :FAM,
IMJA VARCHAR(30) = :IMJA,
OTCH VARCHAR(30) = :OTCH,
DOM VARCHAR(10) = :DOM,
KORP VARCHAR(10) = :KORP,
KVART VARCHAR(20) = :KVART,
PINDEX VARCHAR(6) = :PINDEX,
KLADR_ID BIGINT = :KLADR_ID,
STREET_ID BIGINT = :STREET_ID,
DOP VARCHAR(50) = :DOP,
E_MAIL VARCHAR(50) = :E_MAIL,
ELDOC INTEGER = :ELDOC,
TELEFON VARCHAR(50) = :TELEFON,
ULNAIM VARCHAR(100) = :ULNAIM,
NOTZVUNION INTEGER = :NOTZVUNION)
AS
DECLARE VARIABLE SOCR VARCHAR(10);
DECLARE VARIABLE REG_SIO INTEGER;
DECLARE VARIABLE EXISTCLIENT_ID BIGINT;
DECLARE VARIABLE S VARCHAR(1000) CHARACTER SET UTF8;
DECLARE VARIABLE FIO VARCHAR(100);
BEGIN
IF (CLIENT_ID IS NULL) THEN EXCEPTION ER_PKEY;
IF ((FAM IS NULL) OR (FAM = '')) THEN EXCEPTION ER_ERROR 'Ðе указана фамилиÑ';
IF (PINDEX IS NULL) THEN EXCEPTION ER_ERROR 'Ðе указан почтовый индекÑ';
IF (NOTZVUNION IS NULL) THEN NOTZVUNION = 0;
IF (NOT EXISTS(
SELECT X.CHECKINDEX_ID FROM CHECKINDEX X WHERE X.PINDEX = :PINDEX
)) THEN EXCEPTION ER_ERROR 'Указанный Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ принадлежит не одному почтамту';
IF (DOM = '') THEN DOM = NULL;
IF (KORP = '') THEN KORP = NULL;
IF (KVART = '') THEN KVART = NULL;
IF (E_MAIL = '') THEN E_MAIL = NULL;
IF (KLADR_ID = 0) THEN KLADR_ID = NULL;
IF (KLADR_ID IS NULL) THEN
EXCEPTION ER_ERROR 'Ðе указан адреÑ';
IF (ULNAIM = '') THEN ULNAIM = NULL;
IF (STREET_ID = 0) THEN STREET_ID = NULL;
SELECT K.SOCR, K.REG_SIO FROM KLADR K WHERE K.KLADR_ID = :KLADR_ID
INTO :SOCR, :REG_SIO;
--Ирина Петровна 17.04.13
--IF (BL = 1) THEN EXCEPTION ER_ERROR 'Ðтот Ð°Ð´Ñ€ÐµÑ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²Ð°Ð½';
IF ((SOCR = 'РеÑп') OR (SOCR = 'край') OR (SOCR = 'обл')
OR (SOCR = 'округ') OR (SOCR = 'Ðобл') OR (SOCR = 'Ñ€-н')) THEN
EXCEPTION ER_ERROR 'Ðе корректно указан адреÑ';
/*IF (EXISTS(
SELECT C.CLIENT_ID FROM CLIENT C WHERE
C.KLADR_ID = :KLADR_ID AND C.STREET_ID = :STREET_ID AND C.DOM = :DOM
AND C.KORP = :KORP AND C.KVART = :KVART AND C.FAM = :FAM AND C.IMJA = :IMJA
)) THEN EXCEPTION ER_ERROR 'Клиент Ñ Ñ‚Ð°ÐºÐ¸Ð¼ адреÑом фамилией и именем ÑущеÑтвует';*/
FIO = FAM;
S = 'SELECT FIRST 1 CLIENT_ID FROM CLIENT WHERE FAM = ''' || :FAM || ''' AND KLADR_ID = ' || :KLADR_ID;
IF (IMJA IS NOT NULL) THEN
BEGIN
S = S || ' AND IMJA = ''' || :IMJA || '''';
FIO = FIO || ' ' || IMJA;
END
ELSE
S = S || ' AND IMJA IS NULL';
IF (OTCH IS NOT NULL) THEN
BEGIN
FIO = FIO || ' ' || OTCH;
END
IF (STREET_ID IS NOT NULL) THEN
S = S || ' AND STREET_ID = ' || :STREET_ID;
ELSE
S = S || ' AND STREET_ID IS NULL';
IF (DOM IS NOT NULL) THEN
S = S || ' AND DOM = ''' || :DOM || '''';
ELSE
S = S || ' AND DOM IS NULL';
IF (KORP IS NOT NULL) THEN
S = S || ' AND KORP = ''' || :KORP || '''';
ELSE
S = S || ' AND KORP IS NULL';
IF (KVART IS NOT NULL) THEN
S = S || ' AND KVART = ''' || :KVART || '''';
ELSE
S = S || ' AND KVART IS NULL';
EXISTCLIENT_ID = NULL;
EXECUTE STATEMENT :S INTO :EXISTCLIENT_ID;
IF (EXISTCLIENT_ID IS NOT NULL) THEN EXCEPTION ER_ERROR 'Клиент Ñ Ñ‚Ð°ÐºÐ¸Ð¼ адреÑом фамилией и именем ÑущеÑтвует';
IF (ELDOC IS NULL) THEN ELDOC = 0;
INSERT INTO CLIENT (
CLIENT_ID,
FAM,
IMJA,
OTCH,
KLADR_ID,
STREET_ID,
DOM,
KORP,
KVART,
PINDEX,
AU,
AUDATA,
DOP,
E_MAIL,
ELDOC,
TELEFON,
REG_SIO,
FIO,
ULNAIM,
NOTZVUNION)
VALUES (
:CLIENT_ID,
:FAM,
:IMJA,
:OTCH,
:KLADR_ID,
:STREET_ID,
:DOM,
:KORP,
:KVART,
:PINDEX,
CURRENT_USER,
CURRENT_TIMESTAMP,
:DOP,
:E_MAIL,
:ELDOC,
:TELEFON,
:REG_SIO,
:FIO,
:ULNAIM,
:NOTZVUNION);
END
Можно сделать сначала хранимую процедуру, потом перенести её в UpdateSQL исправив заголовок.
*Rik* писал(а):Mikhail писал(а):Можно пример с EXECUTE BLOCK, а то что то не получается
Только у меня из InsertSQL:Код: Выделить всё
EXECUTE BLOCK(
CLIENT_ID BIGINT = :CLIENT_ID,
FAM VARCHAR(30) = :FAM,
IMJA VARCHAR(30) = :IMJA,
OTCH VARCHAR(30) = :OTCH,
DOM VARCHAR(10) = :DOM,
KORP VARCHAR(10) = :KORP,
KVART VARCHAR(20) = :KVART,
PINDEX VARCHAR(6) = :PINDEX,
KLADR_ID BIGINT = :KLADR_ID,
STREET_ID BIGINT = :STREET_ID,
DOP VARCHAR(50) = :DOP,
E_MAIL VARCHAR(50) = :E_MAIL,
ELDOC INTEGER = :ELDOC,
TELEFON VARCHAR(50) = :TELEFON,
ULNAIM VARCHAR(100) = :ULNAIM,
NOTZVUNION INTEGER = :NOTZVUNION)
AS
DECLARE VARIABLE SOCR VARCHAR(10);
DECLARE VARIABLE REG_SIO INTEGER;
DECLARE VARIABLE EXISTCLIENT_ID BIGINT;
DECLARE VARIABLE S VARCHAR(1000) CHARACTER SET UTF8;
DECLARE VARIABLE FIO VARCHAR(100);
BEGIN
IF (CLIENT_ID IS NULL) THEN EXCEPTION ER_PKEY;
IF ((FAM IS NULL) OR (FAM = '')) THEN EXCEPTION ER_ERROR 'Ðе указана фамилиÑ';
IF (PINDEX IS NULL) THEN EXCEPTION ER_ERROR 'Ðе указан почтовый индекÑ';
IF (NOTZVUNION IS NULL) THEN NOTZVUNION = 0;
IF (NOT EXISTS(
SELECT X.CHECKINDEX_ID FROM CHECKINDEX X WHERE X.PINDEX = :PINDEX
)) THEN EXCEPTION ER_ERROR 'Указанный Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ принадлежит не одному почтамту';
IF (DOM = '') THEN DOM = NULL;
IF (KORP = '') THEN KORP = NULL;
IF (KVART = '') THEN KVART = NULL;
IF (E_MAIL = '') THEN E_MAIL = NULL;
IF (KLADR_ID = 0) THEN KLADR_ID = NULL;
IF (KLADR_ID IS NULL) THEN
EXCEPTION ER_ERROR 'Ðе указан адреÑ';
IF (ULNAIM = '') THEN ULNAIM = NULL;
IF (STREET_ID = 0) THEN STREET_ID = NULL;
SELECT K.SOCR, K.REG_SIO FROM KLADR K WHERE K.KLADR_ID = :KLADR_ID
INTO :SOCR, :REG_SIO;
--Ирина Петровна 17.04.13
--IF (BL = 1) THEN EXCEPTION ER_ERROR 'Ðтот Ð°Ð´Ñ€ÐµÑ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²Ð°Ð½';
IF ((SOCR = 'РеÑп') OR (SOCR = 'край') OR (SOCR = 'обл')
OR (SOCR = 'округ') OR (SOCR = 'Ðобл') OR (SOCR = 'Ñ€-н')) THEN
EXCEPTION ER_ERROR 'Ðе корректно указан адреÑ';
/*IF (EXISTS(
SELECT C.CLIENT_ID FROM CLIENT C WHERE
C.KLADR_ID = :KLADR_ID AND C.STREET_ID = :STREET_ID AND C.DOM = :DOM
AND C.KORP = :KORP AND C.KVART = :KVART AND C.FAM = :FAM AND C.IMJA = :IMJA
)) THEN EXCEPTION ER_ERROR 'Клиент Ñ Ñ‚Ð°ÐºÐ¸Ð¼ адреÑом фамилией и именем ÑущеÑтвует';*/
FIO = FAM;
S = 'SELECT FIRST 1 CLIENT_ID FROM CLIENT WHERE FAM = ''' || :FAM || ''' AND KLADR_ID = ' || :KLADR_ID;
IF (IMJA IS NOT NULL) THEN
BEGIN
S = S || ' AND IMJA = ''' || :IMJA || '''';
FIO = FIO || ' ' || IMJA;
END
ELSE
S = S || ' AND IMJA IS NULL';
IF (OTCH IS NOT NULL) THEN
BEGIN
FIO = FIO || ' ' || OTCH;
END
IF (STREET_ID IS NOT NULL) THEN
S = S || ' AND STREET_ID = ' || :STREET_ID;
ELSE
S = S || ' AND STREET_ID IS NULL';
IF (DOM IS NOT NULL) THEN
S = S || ' AND DOM = ''' || :DOM || '''';
ELSE
S = S || ' AND DOM IS NULL';
IF (KORP IS NOT NULL) THEN
S = S || ' AND KORP = ''' || :KORP || '''';
ELSE
S = S || ' AND KORP IS NULL';
IF (KVART IS NOT NULL) THEN
S = S || ' AND KVART = ''' || :KVART || '''';
ELSE
S = S || ' AND KVART IS NULL';
EXISTCLIENT_ID = NULL;
EXECUTE STATEMENT :S INTO :EXISTCLIENT_ID;
IF (EXISTCLIENT_ID IS NOT NULL) THEN EXCEPTION ER_ERROR 'Клиент Ñ Ñ‚Ð°ÐºÐ¸Ð¼ адреÑом фамилией и именем ÑущеÑтвует';
IF (ELDOC IS NULL) THEN ELDOC = 0;
INSERT INTO CLIENT (
CLIENT_ID,
FAM,
IMJA,
OTCH,
KLADR_ID,
STREET_ID,
DOM,
KORP,
KVART,
PINDEX,
AU,
AUDATA,
DOP,
E_MAIL,
ELDOC,
TELEFON,
REG_SIO,
FIO,
ULNAIM,
NOTZVUNION)
VALUES (
:CLIENT_ID,
:FAM,
:IMJA,
:OTCH,
:KLADR_ID,
:STREET_ID,
:DOM,
:KORP,
:KVART,
:PINDEX,
CURRENT_USER,
CURRENT_TIMESTAMP,
:DOP,
:E_MAIL,
:ELDOC,
:TELEFON,
:REG_SIO,
:FIO,
:ULNAIM,
:NOTZVUNION);
END
Можно сделать сначала хранимую процедуру, потом перенести её в UpdateSQL исправив заголовок.
Спасибо за пример.
А set term не нужно?
Еще один вопрос, как получить первичный ключ (получаемый в триггере) только что вставленной строки? Нужно для вставки в подчиненную таблицу.
PS
Вопрос с получением значения первичного ключа закрыт.
- *Rik*
- постоялец
- Сообщения: 453
- Зарегистрирован: 19.04.2011 12:18:51
- Откуда: Урал
- Контактная информация:
Mikhail писал(а):А set term не нужно?
Нет.
Mikhail писал(а):Еще один вопрос, как получить первичный ключ (получаемый в триггере) только что вставленной строки? Нужно для вставки в подчиненную таблицу.
Если в хранимой процедуре или в EXECUTE BLOCK, то
1 вариант:
Код: Выделить всё
INSERT INTO PARENTTABLE
( ...)
VALUES
(...) RETURNING PARENTTABLE_ID INTO :PARENTTABLE_ID;
INSERT INTO CROSS
(PARENTTABLE_ID, ...) VALUES (:PARENTTABLE_ID, ....);
Здесь PARENTTABLE_ID - переменная.
2й вариант:
До выполнения INSERT сгенерить значения ключа и сохранить в переменной и затем пользоваться по необходимости. Обычно в триггере код такой, что генерация значения происходит если значение первичного ключа отсутствует. Раз мы его сгенерим до выполнения запроса INSERT и подставим его в этот запрос, второй раз значение не сгенерится т.к. значение уже присутствует.
Код: Выделить всё
PARENTTABLE_ID = GEN_ID(GEN_PARENTTABLE_ID, 1);
INSERT INTO PARENTTABLE
(PARENTTABLE_ID, ...)
VALUES
(:PARENTTABLE_ID, ..)
INSERT INTO CROSS
(PARENTTABLE_ID, ...) VALUES (:PARENTTABLE_ID, ....);
Если нужно чтобы после метода Post значение ключа подставлялось в локальный кэш TIBDataSet:
Если просто в InsertSQL нужно сделать чтобы после метода Post в локальный кэш TIBDataSet подставлялось значение первичного ключа, то запрос на вставку будет выглядеть так:
Код: Выделить всё
INSERT INTO MYTABLE
( ...)
VALUES
(...) RETURNING MYTABLE_ID
Если в InsertSQL EXECUTE BLOCK нужно в EXECUTE BLOCK объявить возвращаемый параметр
Код: Выделить всё
EXECUTE Block (
CHKSTAT integer = :chkstat,
KOMMENT varchar(30) = :komment)
RETURNS (
DOCOTK_ID BIGINT)
AS
BEGIN
IF (KOMMENT = '') THEN KOMMENT = NULL;
INSERT INTO DOCOTK (
DATA,
AU,
CHKSTAT,
KOMMENT,
NEVIPOLNIMO)
VALUES (
CURRENT_DATE,
CURRENT_USER,
:CHKSTAT,
:KOMMENT,
0) RETURNING DOCOTK_ID INTO :DOCOTK_ID;
suspend;
END
DOCOTK_ID - объявлен как возвращаемый параметр, его значение будет получено через триггер и через выражение RETURNING. После этого, значение параметра по команде SUSPEND будет отправлено на клиентскую сторону и подставится в локальный кэш TIBDataSet (SUSPEND здесь обязательно).
Имя возвращаемого параметра должно совпадать с именем поля, в которое нужно подставить значение.
ps:
У Вас какой IBX? В оригинальной версии это работать не будет...
*Rik* писал(а):У Вас какой IBX? В оригинальной версии это работать не будет...
Да пишет ошибки синтаксиса.
Firebird Express for Lazarus 1.1.0
- *Rik*
- постоялец
- Сообщения: 453
- Зарегистрирован: 19.04.2011 12:18:51
- Откуда: Урал
- Контактная информация:
Mikhail писал(а):*Rik* писал(а):У Вас какой IBX? В оригинальной версии это работать не будет...
Да пишет ошибки синтаксиса.
Firebird Express for Lazarus 1.1.0
http://visual-t.ru/files/components.7z
В архиве 3 пакета, один из них IBX. Старый нужно снести, новый установить. Тот что в архиве работает как FIBPlus через 2 транзакции, пишущую и читающую.
Для читающей транзакции поставьте параметры

Для пишущей

Читающую транзакцию укажите в TIBDataSet.Transaction
Пишущую в TIBDataSet.UpdateTransaction
