Гость
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет / 16 сообщений из 16, страница 1 из 1
22.08.2019, 10:04
    #39852532
dedRasta
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
Есть такой запрос:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
execute block
returns (
    iID      BIGINT,
    vFNAME   VARCHAR(250),
    vLNAME   VARCHAR(250),
    vMNAME   VARCHAR(250)
    )
as
begin
FOR SELECT
    AU.HOSTUSERID,
    AU.FIRSTNAME,
    LASTNAME,
    AU.MIDDLENAME
from EX_ALL_USER_KEYS AU
into  :iID, :VFNAME, :VLNAME, :VMNAME
 DO begin
--    suspend;
    UPDATE or INSERT into FB_USR
    (        ID,  FNAME,    LNAME,   SNAME, DIST_DAT)
    values (:IID, :vFNAME, :vLNAME, :vMNAME, CAST('21.08.2019' AS DATE))
    MATCHING (ID, FNAME,    LNAME,   SNAME);
--    suspend;
  end
end


Выполняем его в IBExpert.
Если убрать "SUSPEND" - выполняется нормально:

План
PLAN (FB_USR INDEX (FB_USR_IDX1))
PLAN (AU NATURAL)

932 записей было обновлено в таблице FB_USR

570 записей было добавлено в таблицу FB_USR



Если оставить "SUSPEND" до или после - выполняется только UPDATE

PLAN (FB_USR INDEX (FB_USR_IDX1))
PLAN (AU NATURAL)

159 записей было обновлено в таблице FB_USR


А вот если вставить "SUSPEND" в такой запрос:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
execute block
as
declare variable iID BIGINT;
declare variable vFNAME varchar(250);
declare variable vLNAME varchar(250);
declare variable vMNAME varchar(250);
begin
FOR SELECT
    AU.HOSTUSERID,
    AU.FIRSTNAME,
    LASTNAME,
    AU.MIDDLENAME
from EX_ALL_USER_KEYS AU
into  :iID, :VFNAME, :VLNAME, :VMNAME
 DO begin
    UPDATE or INSERT into FB_USR
    (        ID,  FNAME,    LNAME,   SNAME )
    values (:IID, :vFNAME, :vLNAME, :vMNAME)
    MATCHING (ID, FNAME,    LNAME,   SNAME );
    suspend;
  end
end



то получим

План
PLAN (FB_USR INDEX (FB_USR_IDX1))
PLAN (AU NATURAL)

1 записей было обновлено в таблице FB_USR


Без "SUSPEND" работает нормально.


Firebird 2.5.9.27139 (релиз) superserver
Windows 7
...
Рейтинг: 0 / 0
22.08.2019, 10:22
    #39852547
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
dedRasta,

для начала надо изучить как работает suspend и больше никогда не делать таких глупостей. Самое важное твой чудесный блок изменит столько записей сколько будет отфетчено на клиента. Плюс не забыть что suspend вызывает разрыв savepoint и стабильность курсора может быть нарушена
...
Рейтинг: 0 / 0
22.08.2019, 10:26
    #39852552
KreatorXXI
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
dedRasta,

а почитать про suspend в руководстве не судьба? Написано - suspend приостанавливает выполнение всего до тех пор пока не обработаете выходные значения. В случае Execute Block это на стороне клиента. Подозреваю, что и Эксперт не поможет.
Я бы заменил Execute block на хранимку. Для отладки хотя бы.
...
Рейтинг: 0 / 0
22.08.2019, 11:25
    #39852578
hvlad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
dedRasta,

fetch all ?
...
Рейтинг: 0 / 0
22.08.2019, 11:26
    #39852579
hvlad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
KreatorXXIВ случае Execute Block это на стороне клиента.Что - это ???
...
Рейтинг: 0 / 0
22.08.2019, 12:05
    #39852607
KreatorXXI
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
hvladKreatorXXIВ случае Execute Block это на стороне клиента.Что - это ???

Прочитал блок "Входные и выходные параметры" для оператора Execute Block. Может чего не понял или понял не так.
...
Рейтинг: 0 / 0
22.08.2019, 13:19
    #39852681
rdb_dev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
dedRasta, вместо SUSPEND заталкивай во временную таблицу, а после выталкивай оттуда.
...
Рейтинг: 0 / 0
22.08.2019, 13:26
    #39852688
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
rdb_dev, dedRasta

можно как-то так

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
execute block
returns (
    iID      BIGINT,
    vFNAME   VARCHAR(250),
    vLNAME   VARCHAR(250),
    vMNAME   VARCHAR(250)
    )
as
begin
  DELETE FROM GTT_TABLE;
  FOR SELECT
      AU.HOSTUSERID,
      AU.FIRSTNAME,
      LASTNAME,
      AU.MIDDLENAME
    from EX_ALL_USER_KEYS AU
    into  :iID, :VFNAME, :VLNAME, :VMNAME
  DO 
  begin
    UPDATE or INSERT into FB_USR
    (        ID,  FNAME,    LNAME,   SNAME, DIST_DAT)
    values (:IID, :vFNAME, :vLNAME, :vMNAME, CAST('21.08.2019' AS DATE))
    MATCHING (ID, FNAME,    LNAME,   SNAME);

    INSERT INTO GTT_TABLE(iID, vFNAME, vLNAME, vMNAME)
    VALUES (:iID, :vFNAME, :vLNAME, :vMNAME);
  end
  FOR SELECT iID, vFNAME, vLNAME, vMNAME
         FROM GTT_TABLE
         INTO iID, vFNAME, vLNAME, vMNAME
  DO SUSPEND;
end
...
Рейтинг: 0 / 0
22.08.2019, 14:31
    #39852746
Arioch
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
Симонов ДенисСамое важное твой чудесный блок изменит столько записей сколько будет отфетчено на клиента.

Возможно, это и хорошо.

Если в постановке задаче будет важнее показать на клиенте, что реально было изменено, и ничего не пропустить, чем изменить все данные, но показать не все изменения.


Симонов Денис
Код: sql
1.
2.
3.
4.
5.
6.
7.
FOR SELECT
.....
  DO 
  begin
    UPDATE or INSERT
....
    INSERT



Бррр. Понимаю, что на скорую руку. Но всё же лучше от цикла избавиться вообще. Сначала заполняем GTT одной командой insert, потом модифицируем таблицу одной командой MERGE.

Заодно можно будет, если надо, избавиться от холостых update'ов
...
Рейтинг: 0 / 0
22.08.2019, 20:25
    #39852986
rdb_dev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
Симонов Денисrdb_dev, dedRasta
можно как-то такДа, норм!
Только внутри begin...end я бы сделал так:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
UPDATE OR INSERT INTO fb_user (id, fname, lname, sname, dist_dat)
  VALUES (:iid, :vfname, :vlname, :vmname, Cast('21.08.2019' AS DATE))
  MATCHING (id, fname, lname, sname)
  RETURNING id, fname, lname, mname, dist_dat
  INTO: iid, vfname, vlname, vmname, dist_dat;

INSERT INTO gtt_table (id, fname, lname, sname, dist_dat)
  VALUES (:iid, :vfname, :vlname, :vmname, :dist_date);

Чтобы потом долго и упорно не искать концы на случай внесения изменения триггерами таблицы "fb_user", которые могут уже существовать или появятся в будущем.
...
Рейтинг: 0 / 0
22.08.2019, 21:03
    #39853005
dedRasta
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
Всем большое спасибо! Буду изучать.

hvlad, не понял насчет fetch all. Это где можно выставить?
...
Рейтинг: 0 / 0
22.08.2019, 22:41
    #39853026
hvlad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
dedRastahvlad, не понял насчет fetch all. Это где можно выставить?Это на клавиатуре\тулбаре
...
Рейтинг: 0 / 0
23.08.2019, 09:50
    #39853114
dedRasta
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
hvladdedRastahvlad, не понял насчет fetch all. Это где можно выставить?Это на клавиатуре\тулбаре
Не, пора на пенсию. Всегда маячила перед глазами эта кнопка и в голову не приходило просто мышкой на нее показать.
А с ее помощью первый вариант с SUSPEND отрабатывает без проблем:
План
PLAN (FB_USR INDEX (FB_USR_IDX1))
PLAN (AU NATURAL)

932 записей было обновлено в таблице FB_USR

570 записей было добавлено в таблицу FB_USR

Но идея с GTT тоже пригодится - для отчетов о результатах импорта/экспорта.
Еще раз всем спасибо
...
Рейтинг: 0 / 0
23.08.2019, 11:41
    #39853183
Arioch
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
dedRasta,

можно ещё в настройках IBE сделать, чтобы всегда был fetch all, но это на любителя, на больших запросах... сам понимаешь.

-----------

кстати о "сумасшедших идеях" и об уходе от императивного стиля назад к декларативному.

исходный код Расты-Симонова - это два цикла FOR SELECT, с итерацией по одной строчке

мой вариант - INSERT+MERGE, но потом снова цикл, иначе данные из selectable SP/EB не вытолкнешь

а что, если бы на VIEW/GTT можно было бы сделать триггер BEFORE SELECT, который бы её и заполнял по необходимости ?
...
Рейтинг: 0 / 0
23.08.2019, 12:10
    #39853198
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
Arioch,

триггер не нужен, но VIEW может быть создана на основе ХП.

При некоторых условиях можно и вообще без GTT обойтись
MERGE +

Код: sql
1.
2.
3.
4.
5.
FOR SELECT 
  ID,  FNAME,  LNAME,   SNAME, DIST_DAT
FROM FB_USR
WHERE RDB$RECORD_VERSION = CURRENT_TRANSACTION
INTO ...



1. блок должен выполняться в транзакции только один раз, новое выполнение требует новую транзакцию
2. выборка из FB_USR будет использовать NATURAL
3. требуется Firebird 3.0 и выше
...
Рейтинг: 0 / 0
23.08.2019, 17:27
    #39853383
Arioch
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет
Симонов Денистриггер не нужен, но VIEW может быть создана на основе ХП.

VIEW = SELECT FROM SP: а как с материализацией? создавать постоянную таблицу и проверяйт её в процедуре? оптимизатору не понравится на join'ах и громоздко

раздельно SP и таблицу - надо будет две инструкции всегда выполнять, leaking implementation details
...
Рейтинг: 0 / 0
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / При наличии "SUSPEND" в "SELECT FOR" цикле оператор "UPDATE or INSERT" не вставляет / 16 сообщений из 16, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]