Вопрос по IBX

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Вопрос по IBX

Сообщение Mikhail » 30.03.2015 08:53:02

Подскажите, как модифицировать (добавлять) новые данные в таблицу через TIBDataSet (связан через DataSource с DBGrid), если он состоит из нескольких связанных таблиц. Как должен выглядеть UpdateSQL?
Mikhail
энтузиаст
 
Сообщения: 562
Зарегистрирован: 24.10.2013 16:06:47

Re: Вопрос по IBX

Сообщение *Rik* » 30.03.2015 09:55:28

Mikhail писал(а):Подскажите, как модифицировать (добавлять) новые данные в таблицу через TIBDataSet (связан через DataSource с DBGrid), если он состоит из нескольких связанных таблиц. Как должен выглядеть UpdateSQL?

Код: Выделить всё
UPDATE MYTABLE SET
  FIELD1 = :PARAM1,
  FIELD2 = :PARAM2,
  --и так далее
  FIELDN = :PARAMN
WHERE MATABLE_ID = :PARAM_ID
Аватара пользователя
*Rik*
постоялец
 
Сообщения: 426
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re: Вопрос по IBX

Сообщение Mikhail » 30.03.2015 10:03:18

*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;

Изменения вносятся в обе таблицы одновременно.
Mikhail
энтузиаст
 
Сообщения: 562
Зарегистрирован: 24.10.2013 16:06:47

Re: Вопрос по IBX

Сообщение Снег Север » 30.03.2015 10:19:51

Аналогично:
Код: Выделить всё
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
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2993
Зарегистрирован: 27.11.2007 16:14:47

Re: Вопрос по IBX

Сообщение Mikhail » 30.03.2015 10:29:55

Снег Север писал(а):Аналогично:
Код: Выделить всё
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 можно использовать только одну таблицу.
Mikhail
энтузиаст
 
Сообщения: 562
Зарегистрирован: 24.10.2013 16:06:47

Re: Вопрос по IBX

Сообщение *Rik* » 30.03.2015 10:47:17

Mikhail писал(а):Это понятно, а если Dataset это две таблицы связанные через внешний ключ, т.е SelectSQL такой

Сделайте хранимую процедуру для модификации и можете через неё обновлять хоть 10 таблиц одновременно.
(или EXECUTE BLOCK)

В UpdateSQL будет
Код: Выделить всё
EXECUTE PROCEDURE MYPROC(:PARAM1, :PARAM2, :PARAM3)
Аватара пользователя
*Rik*
постоялец
 
Сообщения: 426
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re: Вопрос по IBX

Сообщение Снег Север » 30.03.2015 10:50:49

Mikhail писал(а):В операторе Update можно использовать только одну таблицу.

Ну извините, не знал что там так плохо, в MySQL я такую конструкцию использую постоянно...
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2993
Зарегистрирован: 27.11.2007 16:14:47

Re: Вопрос по IBX

Сообщение Mikhail » 30.03.2015 10:54:04

*Rik* писал(а):
Mikhail писал(а):Это понятно, а если Dataset это две таблицы связанные через внешний ключ, т.е SelectSQL такой

Сделайте хранимую процедуру для модификации и можете через неё обновлять хоть 10 таблиц одновременно.
(или EXECUTE BLOCK)

В UpdateSQL будет
Код: Выделить всё
EXECUTE PROCEDURE MYPROC(:PARAM1, :PARAM2, :PARAM3)


А если все-таки это сделать это на клиенте? Как это обычно делается? На DBGrid такое просто так не получится сделать?
Т.е. форма, датасеты по числу участвующих таблиц, изменение их всех в рамках одной транзакции? Так что-ли?
Mikhail
энтузиаст
 
Сообщения: 562
Зарегистрирован: 24.10.2013 16:06:47

Re: Вопрос по IBX

Сообщение *Rik* » 30.03.2015 10:59:19

Mikhail писал(а):А если все-таки это сделать это на клиенте? Как это обычно делается? На DBGrid такое просто так не получится сделать?
Т.е. форма, датасеты по числу участвующих таблиц, изменение их всех в рамках одной транзакции? Так что-ли?

Можно и так, если в одном запросе надо - то EXECUTE BLOCK, по другому ни как.
Аватара пользователя
*Rik*
постоялец
 
Сообщения: 426
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re: Вопрос по IBX

Сообщение Mikhail » 30.03.2015 17:51:17

*Rik* писал(а):
Mikhail писал(а):А если все-таки это сделать это на клиенте? Как это обычно делается? На DBGrid такое просто так не получится сделать?
Т.е. форма, датасеты по числу участвующих таблиц, изменение их всех в рамках одной транзакции? Так что-ли?

Можно и так, если в одном запросе надо - то EXECUTE BLOCK, по другому ни как.

Можно пример с EXECUTE BLOCK, а то что то не получается :?
Mikhail
энтузиаст
 
Сообщения: 562
Зарегистрирован: 24.10.2013 16:06:47

Сообщение *Rik* » 30.03.2015 18:30:58

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*
постоялец
 
Сообщения: 426
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re:

Сообщение Mikhail » 30.03.2015 18:45:07

*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
Вопрос с получением значения первичного ключа закрыт.
Mikhail
энтузиаст
 
Сообщения: 562
Зарегистрирован: 24.10.2013 16:06:47

Re: Re:

Сообщение *Rik* » 30.03.2015 19:22: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*
постоялец
 
Сообщения: 426
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re: Вопрос по IBX

Сообщение Mikhail » 30.03.2015 19:45:10

*Rik* писал(а):У Вас какой IBX? В оригинальной версии это работать не будет...

Да пишет ошибки синтаксиса.
Firebird Express for Lazarus 1.1.0
Mikhail
энтузиаст
 
Сообщения: 562
Зарегистрирован: 24.10.2013 16:06:47

Re: Вопрос по IBX

Сообщение *Rik* » 30.03.2015 19:59:56

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
Аватара пользователя
*Rik*
постоялец
 
Сообщения: 426
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 30

Рейтинг@Mail.ru