|
INSERT INTO ... SELECT
|
|||
---|---|---|---|
#18+
Здравствуйте! Помогите, пожалуйста, разобраться с таким вопросом: Имеется две таблицы, обзовем для простоты Base и Import. Задача: обновить таблицу Base данными из таблицы Import, вставлять только те записи, которых нет в Base Реализовал так: Код: sql 1. 2. 3. 4.
Перед вставкой проверяется количество добавляемых строк: Код: sql 1. 2. 3.
Все вроде работает, но в некоторых случаях количество добавленных строк меньше, чем показывает запрос с Count. При анализе выяснилось, что имело место быть задвоение одинаковых строк в таблице Import. Но ведь подзапрос не проверяет задвоения в таблице Import, он реализует разность между Base и Import? Такой результат можно ожидать только в том случае, если внешний подзапрос в запросе INSER INTO ... SELECT выполняется не один раз перед вставкой, а повторяется для каждой строки. Догуглится до истины я не смог, поэтому прошу ответить, если кто знает: в запросе Код: sql 1.
подзапрос выполняется один раз для всего массива данных или для каждой строки последовательно в процессе вставки? ... |
|||
:
Нравится:
Не нравится:
|
|||
19.10.2017, 14:13 |
|
INSERT INTO ... SELECT
|
|||
---|---|---|---|
#18+
Код: sql 1. 2. 3. 4.
DISTINCT уберет дублирующие строки. Вы не описали, как именно вы выполняете запрос на добавление и как проверяете кол-во записей. Это сохраненные запросы или текст формируется в процедуре? Для какой цели нужно знать количество записей для добавления именно перед выполнением? Кол-во добавленных записей можно получить с помощью RecordsAffected (метод DAO, аргумент ADO). Если нужно иметь возможность отменить результат, то можно применить транзакцию. Также, если добавление выполнять методом DoCmd.RunSQL (DoCmd.OpenQuery) с включенными сообщениями, то Акс сам сообщит вам предполагаемое кол-во записей и запросит действие. В принципе, без секции INSERT INTO Base({..список полей..}) это будет запрос на выборку, на котором можно открыть Recodset и получить количество записей, а затем добавить секцию и выполнить добавление. Код: sql 1.
подзапрос выполняется один раз для всего массива данных или для каждой строки последовательно в процессе вставки? Как раз с оператором EXISTS подзапрос выполняется для каждой строки последовательно в процессе выборки ... |
|||
:
Нравится:
Не нравится:
|
|||
19.10.2017, 14:57 |
|
INSERT INTO ... SELECT
|
|||
---|---|---|---|
#18+
Анатолий ( Киев )Как раз с оператором EXISTS подзапрос выполняется для каждой строки последовательно в процессе выборки За Access не скажу, но по всем канонам SQL и согласно стандарту exists выполняется единожды ПЕРЕД началом вставки. И задвоение строки в источнике ведет либо к ошибке, если задвоение в таблице-назначении недопустимо, либо к вставке ДВУХ строк. Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16.
(строк обработано: 2) x ----------- 1 1 Сообщение 2627, уровень 14, состояние 1, строка 12 Нарушено "PK__#B5F4CC5__3BD019E5483CC9E4" ограничения PRIMARY KEY. Не удается вставить повторяющийся ключ в объект "dbo.@tt". Повторяющееся значение ключа: (1). Выполнение данной инструкции было прервано. x ----------- ... |
|||
:
Нравится:
Не нравится:
|
|||
19.10.2017, 15:31 |
|
INSERT INTO ... SELECT
|
|||
---|---|---|---|
#18+
Анатолий ( Киев ), авторDISTINCT уберет дублирующие строки. Вы не описали, как именно вы выполняете запрос на добавление и как проверяете кол-во записей. Это сохраненные запросы или текст формируется в процедуре? Для какой цели нужно знать количество записей для добавления именно перед выполнением? В принципе, без секции INSERT INTO Base({..список полей..}) это будет запрос на выборку, на котором можно открыть Recodset и получить количество записей, а затем добавить секцию и выполнить добавление. INSERT INTO ... SELECT подзапрос выполняется один раз для всего массива данных или для каждой строки последовательно в процессе вставки? Как раз с оператором EXISTS подзапрос выполняется для каждой строки последовательно в процессе выборки Да там все очень просто: из соседнего отдела попросили помочь с обновлением таблиц, я посидел, набросал маленькую примитивную программку, которая считывала простенькую табличку и по ее данным составляла запрос (там очень муторно руками писать, так как в импортируемой табличке поля текстовые, а в целевой - словари, соответственно нужно писать вагон INNER JOIN'ов, полей очень много - так что на VBA накидал генерилку запроса. Количество записей показывается оператору, для контроля - если что не так, он не даст подтверждение на добавление. Именно так и отловили несоответствие: предложили 2100 записей вставить, а вставили в итоге только 2050, после чего пришли ко мне разбираться в чем дело. Как сейчас работает - все всех полностью устраивает, мне просто захотелось понять, почему такое неожиданное для меня поведение - я себя кулаком в грудь бил, что так быть не должно, а оно так... ))) По поводу Exists: он, конечно, исполняется многократно, но для каждой строки внешнего по отношению к нему SELECT'а, а тут, получается, SELECT запускал обновление подзапроса для каждой своей строки в процессе вставки? Вот что для меня неожиданно... Спасибо за ответ. ... |
|||
:
Нравится:
Не нравится:
|
|||
20.10.2017, 15:36 |
|
INSERT INTO ... SELECT
|
|||
---|---|---|---|
#18+
aleks222, авторЗа Access не скажу, но по всем канонам SQL и согласно стандарту exists выполняется единожды ПЕРЕД началом вставки. И задвоение строки в источнике ведет либо к ошибке, если задвоение в таблице-назначении недопустимо, либо к вставке ДВУХ строк. Во-во, и я ожидал именно такого поведения... (Точно не скажу, не копал, но по моему в Access нельзя составные индексы применять? Так что ожидал вставки двух строк.) Странно все это... Спасибо за ответ. ... |
|||
:
Нравится:
Не нравится:
|
|||
20.10.2017, 15:39 |
|
|
start [/forum/topic.php?fid=45&fpage=64&tid=1611989]: |
0ms |
get settings: |
11ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
36ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
46ms |
get tp. blocked users: |
2ms |
others: | 15ms |
total: | 147ms |
0 / 0 |