Страница 1 из 1
update or insert и подзапрос в качестве значения в values
Добавлено: 02 июн 2008, 11:09
mdfv
так вот данная конструкция не вставляет записи.
Причем логику я так и не понял. Один раз как-то удалось вставить, потом на других данных перестало работать. Только если вставлять непосредственное значение.
перечитал релноты в разделе UPDATE OR INSERT Statement
и не нашел ничего подозрительного. Не нашел случая чтоб небыло вставки или апдейта. В статистике только чтение происходит из подзапросов а инсерта нету.
вот так не работает(точнее вставило чудом один раз на одних данных, а на других нет):
Код: Выделить всё
update or insert into ULRELTXTREL
(ADRNAME,ADRSOCR,SUL)
values(
(select (ADRNAME) from KLADR where ADRID=111111111111),
(select (ADRSOCR) from KLADR where ADRID=111111111111),
'УЛ ЛЕНИНА'
)
MATCHING(ADRNAME,ADRSOCR,SUL)
а так работает:
Код: Выделить всё
update or insert into ULRELTXTREL
(ADRNAME,ADRSOCR,SUL)
values(
'ЛЕНИНА',
'УЛ',
'УЛ ЛЕНИНА'
)
MATCHING(ADRNAME,ADRSOCR,SUL)
Причем если вставить прямым текстом(как в последнем примере) то потом вставка с подзапросами начинает таки апдейтить.
Добавлено: 02 июн 2008, 11:22
hvlad
Простой воспроизводимый пример поможет найти причину проблемы.
Добавлено: 02 июн 2008, 12:10
mdfv
Server Version: WI-V2.1.0.17798 Firebird 2.1
База:
Код: Выделить всё
SET SQL DIALECT 3;
SET NAMES WIN1251;
SET CLIENTLIB 'FBCLIENT.dll';
CREATE DATABASE 'testdb.fdb'
USER 'SYSDBA' PASSWORD 'masterkey'
PAGE_SIZE 4096
DEFAULT CHARACTER SET WIN1251;
CREATE GENERATOR GEN_ULRELTXTREL_ID;
SET GENERATOR GEN_ULRELTXTREL_ID TO 3;
CREATE TABLE KLADR (
ADRID BIGINT NOT NULL,
ADRNAME VARCHAR(40),
ADRSOCR VARCHAR(10)
);
CREATE TABLE ULRELTXTREL (
PKULT INTEGER NOT NULL,
ADRNAME VARCHAR(40),
ADRSOCR VARCHAR(10),
SUL VARCHAR(40)
);
ALTER TABLE KLADR ADD CONSTRAINT PK_KLADR PRIMARY KEY (ADRID);
ALTER TABLE ULRELTXTREL ADD CONSTRAINT PK_ULRELTXTREL PRIMARY KEY (PKULT);
CREATE INDEX ULRELTXTREL_ALL ON ULRELTXTREL (ADRNAME, ADRSOCR, SUL);
SET TERM ^ ;
/* Trigger: ULRELTXTREL_BI */
CREATE TRIGGER ULRELTXTREL_BI FOR ULRELTXTREL
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.pkult is null) then
new.pkult = gen_id(gen_ulreltxtrel_id,1);
end
^
SET TERM ; ^
Данные:
Код: Выделить всё
insert into KLADR
(ADRID,
ADRNAME,
ADRSOCR
)
values
(111111111111,
'ЛЕНИНА',
'УЛ'
)
Если выполнить такой запрос:
Код: Выделить всё
update or insert into ULRELTXTREL
(ADRNAME,ADRSOCR,SUL)
values(
(select (ADRNAME) from KLADR where ADRID=111111111111),
(select (ADRSOCR) from KLADR where ADRID=111111111111),
'УЛ ЛЕНИНА'
)
MATCHING(ADRNAME,ADRSOCR,SUL)
То вставки не происходит. И в статистике происходит только 2 индексированных чтения из KLADR.
А если вставить несуществующую в KLADR запись
к примеру:
Код: Выделить всё
update or insert into ULRELTXTREL
(ADRNAME,ADRSOCR,SUL)
values(
(select (ADRNAME) from KLADR where ADRID=111111111112),
(select (ADRSOCR) from KLADR where ADRID=111111111112),
'ПЕР ЛЕНИНА'
)
MATCHING(ADRNAME,ADRSOCR,SUL)
то чтений естественно нет, но вставка с нуллами уже происходит.
Добавлено: 02 июн 2008, 12:42
mdfv
Хочется просто узнать - это баг сервера/железа или баг в голове и надо внимательнее читать документы и писать по другому.....
Добавлено: 02 июн 2008, 12:49
hvlad
UPDATE OR INSERT это эквивалент
Код: Выделить всё
UPDATE ...
IF (ROW_COUNT = 0)
THEN INSERT ...
Т.к. у тебя есть SELECT'ы, то ROW_COUNT никак не 0, посему в твоём случае UPDATE OR INSERT не подходит.
А подходит тебе MERGE :
Код: Выделить всё
MERGE INTO ULRELTXTREL U
USING (SELECT * FROM KLADR WHERE ADRID=111111111111) K
ON U.ADRNAME = K.ADRNAME AND U.ADRSOCR = K.ADRSOCR
WHEN MATCHED THEN UPDATE SET SUL = 'УЛ ЛЕНИНА'
WHEN NOT MATCHED THEN INSERT (ADRNAME, ADRSOCR, SUL)
VALUES (K.ADRNAME, K.ADRSOCR, 'УЛ ЛЕНИНА')
Добавлено: 02 июн 2008, 13:07
mdfv
Спасибо.
А в документации такие не сразу очевидные вещи могут описать?
Или другой версии реализации может быть по другому и там будет проверяться именно апдейт, а не его составляющие, что по идее правильнее?
Добавлено: 02 июн 2008, 13:15
hvlad
Правильнее всегда использовать MERGE при обновлении таблицы данными из других таблиц.
Детали реализации описаны, например,
здесь
Добавлено: 05 июн 2008, 09:39
Tonal
hvlad писал(а):UPDATE OR INSERT это эквивалент
Код: Выделить всё
UPDATE ...
IF (ROW_COUNT = 0)
THEN INSERT ...
Т.к. у тебя есть SELECT'ы, то ROW_COUNT никак не 0, посему в твоём случае UPDATE OR INSERT не подходит.
Мне кажется, что в таком случае нужно запретить в использование вложенных SELECT-ов в конструкции UPDATE OR INSERT поскольку она в этом случае вырождается в UPDATE и смысла не имеет.
Либо изменять логику и не учитывать ROW_COUNT от вложенных SELECT-ов.
Добавлено: 05 июн 2008, 11:00
mdfv
Кстати MERGE INTO в документации где-нибудь описано?
Или только в материалах конференций, выступлений?
Добавлено: 05 июн 2008, 11:19
hvlad
mdfv писал(а):Кстати MERGE INTO в документации где-нибудь описано?
Или только в материалах конференций, выступлений?
Нет конечно, только на ушкО рассказываем
Ты документацию-то открывал ? Где не нашёл ?
Добавлено: 05 июн 2008, 11:28
mdfv
Здесь не нашел:
Firebird 2.1 Release Notes
14 April 2008 - Document v. 0210_53 - for Firebird 2.1
А где надо?
Несколько раз смотрел.
UPDATE OR INSERT есть
а MERGE нет.
Добавлено: 05 июн 2008, 11:59
WildSery
Добавлено: 05 июн 2008, 12:03
mdfv
Я смотрел pdf который с сервером идет.
В нем нет.
Добавлено: 05 июн 2008, 12:47
hvlad
mdfv писал(а):Я смотрел pdf который с сервером идет.
В нем нет.
Да, действительно нет. Значит пропустили. И в доке бывают баги
Можешь скачать свежую
версию, там есть