powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / merge when not matched by source
6 сообщений из 6, страница 1 из 1
merge when not matched by source
    #39936409
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
create table TGT (
    EXTID  integer not null,
    ID     integer not null,
    ATTR   varchar(20)
);

create table SRC (
    ID     integer not null,
    ATTR   varchar(20)
);



Задача: для некоторого значения :EXTID синхронизовать соответствующую часть таблицы TGT c таблицей SRC, то есть совпадающие по ID записи обновить, отсутствующие в TGT, но существующие в SRC - добавить, лишние - удалить.

Хочу использовать оператор merge, который вроде бы как раз для таких задач и создан. Никогда раньше с ним не работал, прошу не бить тапками. Пишу нечто следующее:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
merge
  into
     TGT
  using
     SRC
  on
     ( ( TGT.EXTID = :EXTID ) and ( TGT.ID = SRC.ID ) )

  --when not matched by source then

      --delete

  when matched then

    update set TGT.ATTR = SRC.ATTR

  when not matched then

    insert  ( EXTID, ID, ATTR )  values ( :EXTID, SRC.ID, SRC.ATTR )



Вопросов, собственно, 2:

1) Как правильно (лучше, эффективнее) поставить условие по EXTID?

2) Как удалять лишние записи, то есть те, которые есть в TGT, но которых нет в SRC?
Подсмотрел в MSSQL кляузу by source специально для этого случая, но Firebird такую не поддерживает. Как бы её сэмулировать?

Firebird 3.0.2
...
Рейтинг: 0 / 0
merge when not matched by source
    #39936558
KreatorXXI
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shalamyansky,

есть кляуза "when no matched and condition". Т.е. можно задать несколько условий в одном операторе.
...
Рейтинг: 0 / 0
merge when not matched by source
    #39936566
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shalamyansky,

1. эффективнее в ON или в using(select ... where ...), ибо может задействовать индекс, но это не всегда подходит. Иногда лучше дополнить условия WHEN MATCHED и WHEN NOT MATCHED. А если таких условий несколько, то это делать придётся в любом случае

2. В рамках одного запрос никак. Можно разбить на два запроса и засунуть их в EXECUTE BLOCK
...
Рейтинг: 0 / 0
merge when not matched by source
    #39936707
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Денис

2. В рамках одного запрос никак. Можно разбить на два запроса


И каков будет запрос на удаление лишних записей? Подозреваю, что delete where not exists, а это оказывается нехорошо, как объясняется в теме ниже . А посредством merge удалить лишние записи получается, что не получается.
...
Рейтинг: 0 / 0
merge when not matched by source
    #39936711
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Но это не большая беда. Потому что можно составить вот такую процедуру, где за один проход сразу по двум курсорам и обновить, и вставить, и удалить лишние:

Код: 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.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
create table TGT (
    EXTID  integer not null,
    ID     integer not null,
    ATTR   varchar(20)
);
alter table TGT add constraint "pk_TGT" primary key (EXTID, ID);

create table SRC (
    ID    integer not null,
    ATTR  varchar(20)
);
alter table SRC add constraint "pk_SRC" primary key (ID);

set term ^ ;

create or alter procedure "DoMerge"(
    EXTID integer
)as

    -- target table window sorted by ID
    declare T cursor for (
        select
              TGT.ID   as ID
            , TGT.ATTR as ATTR
          from
            TGT
          where
            ( TGT.EXTID = :EXTID )
          order by
            TGT.ID
    );

    -- source table sorted by ID
    declare S cursor for (
        select
              SRC.ID   as ID
            , SRC.ATTR as ATTR
          from
            SRC
          order by
            SRC.ID
    );

    declare variable T_ID   integer;
    declare variable T_ATTR varchar(20);
    declare variable S_ID   integer;
    declare variable S_ATTR varchar(20);

begin

    open T;
    open S;

    fetch T into :T_ID, :T_ATTR;
    fetch S into :S_ID, :S_ATTR;

    while( ( :T_ID is not null ) or ( :S_ID is not null ) )do begin
        
        if( :T_ID = :S_ID )then begin

            if( :T_ATTR is distinct from :S_ATTR )then begin
                update
                    TGT
                  set
                    TGT.ATTR = :S_ATTR
                  where
                    current of T
                ;
            end

            :T_ID = null; T_ATTR = null;
            fetch T into :T_ID, :T_ATTR;
            :S_ID = null; S_ATTR = null;
            fetch S into :S_ID, :S_ATTR;

        end else if( ( :T_ID is null ) or ( :S_ID < :T_ID ) )then begin

            insert into
              TGT
                     (  EXTID,    ID,    ATTR )
              values ( :EXTID, :S_ID, :S_ATTR )
            ;

            :S_ID = null; S_ATTR = null;
            fetch S into :S_ID, :S_ATTR;

        end else if( ( :S_ID is null ) or ( :S_ID > :T_ID ) )then begin

            delete from
                TGT
              where
                current of T
            ;

            :T_ID = null; T_ATTR = null;
            fetch T into :T_ID, :T_ATTR;

        end else begin  --just in case

            :T_ID = null; T_ATTR = null;
            fetch T into :T_ID, :T_ATTR;
            :S_ID = null; S_ATTR = null;
            fetch S into :S_ID, :S_ATTR;

        end

    end

    close S;
    close T;

end^

set term ; ^
...
Рейтинг: 0 / 0
merge when not matched by source
    #39936722
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shalamyansky
Симонов Денис

2. В рамках одного запрос никак. Можно разбить на два запроса


И каков будет запрос на удаление лишних записей? Подозреваю, что delete where not exists, а это оказывается нехорошо, как объясняется в теме ниже . А посредством merge удалить лишние записи получается, что не получается.


если у кого-то что-то тормозит, то это не обязательно будет тормозить у тебя. У автора того топика весьма витиеватый запрос
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / merge when not matched by source
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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