powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / INSERT INTO ... SELECT
5 сообщений из 5, страница 1 из 1
INSERT INTO ... SELECT
    #39538722
iMerlin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте!

Помогите, пожалуйста, разобраться с таким вопросом:

Имеется две таблицы, обзовем для простоты Base и Import.

Задача: обновить таблицу Base данными из таблицы Import, вставлять только те записи, которых нет в Base

Реализовал так:
Код: sql
1.
2.
3.
4.
INSERT INTO Base({..список полей..})
SELECT ({..список полей..}) FROM Import WHERE NOT EXISTS(
SELECT ({..список полей..}) FROM Base WHERE Base.field1=Import.field1 And Base.field2=Import.field2 And ... And Base.fieldn=Import.fieldn
))


Перед вставкой проверяется количество добавляемых строк:

Код: sql
1.
2.
3.
SELECT (Count(*)) FROM Import WHERE NOT EXISTS(
SELECT ({..список полей..}) FROM Base WHERE Base.field1=Import.field1 And Base.field2=Import.field2 And ... And Base.fieldn=Import.fieldn
))



Все вроде работает, но в некоторых случаях количество добавленных строк меньше, чем показывает запрос с Count. При анализе выяснилось, что имело место быть задвоение одинаковых строк в таблице Import. Но ведь подзапрос не проверяет задвоения в таблице Import, он реализует разность между Base и Import? Такой результат можно ожидать только в том случае, если внешний подзапрос в запросе INSER INTO ... SELECT выполняется не один раз перед вставкой, а повторяется для каждой строки.
Догуглится до истины я не смог, поэтому прошу ответить, если кто знает: в запросе
Код: sql
1.
INSERT INTO ... SELECT

подзапрос выполняется один раз для всего массива данных или для каждой строки последовательно в процессе вставки?
...
Рейтинг: 0 / 0
INSERT INTO ... SELECT
    #39538768
Код: sql
1.
2.
3.
4.
INSERT INTO Base({..список полей..})
SELECT DISTINCT ({..список полей..}) FROM Import WHERE NOT EXISTS(
SELECT ({..список полей..}) FROM Base WHERE Base.field1=Import.field1 And Base.field2=Import.field2 And ... And Base.fieldn=Import.fieldn
))

DISTINCT уберет дублирующие строки.
Вы не описали, как именно вы выполняете запрос на добавление и как проверяете кол-во записей. Это сохраненные запросы или текст формируется в процедуре?
Для какой цели нужно знать количество записей для добавления именно перед выполнением?
Кол-во добавленных записей можно получить с помощью RecordsAffected (метод DAO, аргумент ADO). Если нужно иметь возможность отменить результат, то можно применить транзакцию.
Также, если добавление выполнять методом DoCmd.RunSQL (DoCmd.OpenQuery) с включенными сообщениями, то Акс сам сообщит вам предполагаемое кол-во записей и запросит действие.

В принципе, без секции INSERT INTO Base({..список полей..}) это будет запрос на выборку, на котором можно открыть Recodset и получить количество записей, а затем добавить секцию и выполнить добавление.
Код: sql
1.
INSERT INTO ... SELECT

подзапрос выполняется один раз для всего массива данных или для каждой строки последовательно в процессе вставки? Как раз с оператором EXISTS подзапрос выполняется для каждой строки последовательно в процессе выборки
...
Рейтинг: 0 / 0
INSERT INTO ... SELECT
    #39538815
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Анатолий ( Киев )Как раз с оператором EXISTS подзапрос выполняется для каждой строки последовательно в процессе выборки

За Access не скажу, но по всем канонам SQL и согласно стандарту exists выполняется единожды ПЕРЕД началом вставки.
И задвоение строки в источнике ведет либо к ошибке, если задвоение в таблице-назначении недопустимо, либо к вставке ДВУХ строк.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
declare @t table(x int);

insert @t(x) select x     
               from ( select 1 as x union all select 1 as x ) as t
               where not exists( select * from @t where x = t.x )

select * from @t;


declare @tt table(x int primary key);

insert @tt(x) select x     
               from ( select 1 as x union all select 1 as x ) as t
               where not exists( select * from @tt where x = t.x )

select * from @tt;



(строк обработано: 2)
x
-----------
1
1

Сообщение 2627, уровень 14, состояние 1, строка 12
Нарушено "PK__#B5F4CC5__3BD019E5483CC9E4" ограничения PRIMARY KEY. Не удается вставить повторяющийся ключ в объект "dbo.@tt". Повторяющееся значение ключа: (1).
Выполнение данной инструкции было прервано.
x
-----------
...
Рейтинг: 0 / 0
INSERT INTO ... SELECT
    #39539615
iMerlin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Анатолий ( Киев ),

авторDISTINCT уберет дублирующие строки.
Вы не описали, как именно вы выполняете запрос на добавление и как проверяете кол-во записей. Это сохраненные запросы или текст формируется в процедуре?
Для какой цели нужно знать количество записей для добавления именно перед выполнением?

В принципе, без секции INSERT INTO Base({..список полей..}) это будет запрос на выборку, на котором можно открыть Recodset и получить количество записей, а затем добавить секцию и выполнить добавление.
INSERT INTO ... SELECT
подзапрос выполняется один раз для всего массива данных или для каждой строки последовательно в процессе вставки?
Как раз с оператором EXISTS подзапрос выполняется для каждой строки последовательно в процессе выборки

Да там все очень просто: из соседнего отдела попросили помочь с обновлением таблиц, я посидел, набросал маленькую примитивную программку, которая считывала простенькую табличку и по ее данным составляла запрос (там очень муторно руками писать, так как в импортируемой табличке поля текстовые, а в целевой - словари, соответственно нужно писать вагон INNER JOIN'ов, полей очень много - так что на VBA накидал генерилку запроса.
Количество записей показывается оператору, для контроля - если что не так, он не даст подтверждение на добавление. Именно так и отловили несоответствие: предложили 2100 записей вставить, а вставили в итоге только 2050, после чего пришли ко мне разбираться в чем дело.
Как сейчас работает - все всех полностью устраивает, мне просто захотелось понять, почему такое неожиданное для меня поведение - я себя кулаком в грудь бил, что так быть не должно, а оно так... )))
По поводу Exists: он, конечно, исполняется многократно, но для каждой строки внешнего по отношению к нему SELECT'а, а тут, получается, SELECT запускал обновление подзапроса для каждой своей строки в процессе вставки? Вот что для меня неожиданно...

Спасибо за ответ.
...
Рейтинг: 0 / 0
INSERT INTO ... SELECT
    #39539618
iMerlin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
aleks222,
авторЗа Access не скажу, но по всем канонам SQL и согласно стандарту exists выполняется единожды ПЕРЕД началом вставки.
И задвоение строки в источнике ведет либо к ошибке, если задвоение в таблице-назначении недопустимо, либо к вставке ДВУХ строк.

Во-во, и я ожидал именно такого поведения... (Точно не скажу, не копал, но по моему в Access нельзя составные индексы применять? Так что ожидал вставки двух строк.)
Странно все это...

Спасибо за ответ.
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / INSERT INTO ... SELECT
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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