Подскажите, реально ли для MySQL через ADODB выполнить пакет вида
UPD ATE tbl SET name='один' WHERE id = '1';
UPD ATE tbl SET name='два' WHERE id = '2';
UPDATE tbl SE T name='три' WHERE id = '3';...
Попытка запихать запрос такого вида в АДО.Execute(); приводит к ошибке
[MySQL][ODBC 5.3(w) Driver][mysqld-5.1.73]You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UPDATE tbl SE T...
А выполнение построчно очень долгое.
(1) SirStefan, реально . проверено. ты наверное неверно формируешь запрос.(синтаксическая ошибка). но я посоветую сделать по другому, значительно быстрее сделать временную таблицу, потом update через join
(4) SirStefan, через CRE ATE TABLE либо CREATE TEMPORARY TABLE , просто я не знаю какую конкретно табличку надо, в смысле какие поля. но в интернете можно найти очень много мануалов по описанию данного выражения.(например можно вообще лениво поступить CREATE TEMPORARY TABLE temptable SEL ECT * FR OM tbl LIMIT 0; в итоге будет пустая временная таблица идентичной структуры исходной таблицы) вставка это уже в зависимости от того в каком виде входные данные. можно вообще одной командой практически импортировать csv файл (http://dev.mysql.com/doc/refman/5.7/en/load-data.html) либо формировать команды INS ERT INTO temptable (`field1`,`field2`) VALUES (value11,value21),(value12,value22),(val ue13,value23) и т.д. (опытным путем установить сколько оптимально этих VALUES). Затем сделать UPD ATE tbl table1 JOIN temptable tt ON table1.id=tt.id SE T table1.`name`=tt.name; и это действительно будет значительно быстрее чем одиночные update
(5), про виртуальную таблицу попробую, спасибо. Но я имел в виду, что ее все равно не получится сформировать одним пакетным запросом. Не воспринимает ODBC драйвер почему то ";". При этом из админки все пакетные запросы отрабатывают на ура. Вот и пытаюсь понять в чем дело тут может быть.
INSERT у меня так и реализован - одним запросом передаются все данные. А вот с UPDATE уже так не выходит.
(6) SirStefan, у меня отрабатывает ADODB с ; то что я описывал это проверенное решение. тут дело в чем-то ином. (если запрос из под админки работает, а из 1С + ADODB не работает, смею предположить, что быть может с кодировками что-то не так, надо причину искать)
Не работает.
Произошла исключительная ситуация (Microsoft OLE DB Provider for ODBC Drivers): [MySQL][ODBC 5.3(w) Driver][mysqld-5.1.73]You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSЕRT INTО tbl (id,name) VALUES ('0002','ДВА')' at line 1
Просто INSЕRT INTО tbl (id,name) VALUES ('0001','РАЗ') работает отлично.
P.S. INSЕRT ставил только для проверки запроса. Интересует как заставить работать UPDATE
(8) SirStefan, а какая версия Mysql? (не драйвера, а версия СУБД) . и еще надо попробовать разделить команды символом новой строки.
"INSЕRT INTО tbl (id,name) VALUES ('0001','РАЗ');"+ Символы.ПС+ " INSЕRT INTО tbl (id,name) VALUES ('0002','ДВА')"
ps в принципе можно и таким образом вставлять во временную таблицу "INSЕRT INTО tbl (id,name) VALUES ('0001','РАЗ'), ('0002','ДВА');" это будет быстрее. затем сделать одной командой update. выполнять команды отдельно, необязательно их пытаться запихнуть в один большой запрос.
(15) SirStefan, да потому что update ты одиночные делаешь. поэтому. а вовсе не из-за последовательного выполнения команд в принципе. ты ж даже не пробовал , что я тебе писал. в блоге по ссылке, что я давал, там вообще запрос менее секунды исполняется. у меня из практики 100 000 update аналогично очень быстро выполнялись.
(15) SirStefan, вот такой говнокод сработает не просто очень медленно, а очень даже быстро. (в качестве временной таблицы в данному примере обычная таблица, поэтому она очищается вначале)
ConnectionString = "некая строка соединения";
Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.ConnectionString = ConnectionString;
Попытка
Соединение.Open();
Исключение
ОбщегоНазначения.СообщитьОбОшибке(ОписаниеОшибки());
КонецПопытки;
Попытка
Соединение.Execute("truncate table temptable;");
Соединение.Execute("ALT ER TABLE temptable AUTO_INCREMENT = 1");
Исключение
ОбщегоНазначения.СообщитьОбОшибке(ОписаниеОшибки());
Возврат;
КонецПопытки;
Текст = Новый ТекстовыйДокумент;
Текст.ДобавитьСтроку("INS ERT IN TO temptable (`field1`,`field2`) VALUES ");
Для i=0 По ТЗ.Количество()-2 Цикл
Строка=ТЗ[i];
Если i<>0 И i%100=0 Тогда
ТекстЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("('%1','%2')",Строка.field1,Формат(Строка.field2,"ЧРД=.; ЧГ="));
Текст.ДобавитьСтроку(ТекстЗапроса);
Текст.ДобавитьСтроку(";");
Текст.ДобавитьСтроку(Символы.ПС);
Попытка
Соединение.Execute(Текст.ПолучитьТекст());
Исключение
ОбщегоНазначения.СообщитьОбОшибке(ОписаниеОшибки());
Прервать;
КонецПопытки;
Текст = Новый ТекстовыйДокумент;
Текст.ДобавитьСтроку("INS ERT IN TO temptable (`field1`,`field2`) VALUES ");
Иначе
ТекстЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("('%1','%2')",Строка.field1,Формат(Строка.field2,"ЧРД=.; ЧГ="));
Текст.ДобавитьСтроку(ТекстЗапроса+",");
КонецЕсли;
КонецЦикла;
Строка=ТЗ[ТЗ.Количество()-1];
ТекстЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("('%1','%2')",Строка.field1,Формат(Строка.field2,"ЧРД=.; ЧГ="));
Текст.ДобавитьСтроку(ТекстЗапроса);
Текст.ДобавитьСтроку(";");
Попытка
Соединение.Execute(Текст.ПолучитьТекст());
Исключение
ОбщегоНазначения.СообщитьОбОшибке(ОписаниеОшибки());
Возврат;
КонецПопытки;
Попытка
Соединение.Execute("UPD ATE tbl table1 JOIN temptable ttt ON table1.field1=ttt.field1 SE T p.field2=ttt.field2;");
Исключение
ОбщегоНазначения.СообщитьОбОшибке(ОписаниеОшибки());
Возврат;
КонецПопытки;
Ну я ответ на первый вопрос дал, как сделать не используя построчно - в этом случае 1 execute в 1С будет, а результат именно тот который дали бы 3 запроса из того же первого сообщения построчно.
Прошло больше трех лет с вопроса, но ответа нет и не только на этом форуме. Поэтому мне пришлось изучить вопрос и я доложу о результатах.
Во-первых SirStefan совершенно прав. Проблема в MySQL, т.к. он не умеет выполнить в одном запросе пакет из нескольких самостоятельных запросов. Это неизменно ведет к сообщению о синтаксической ошибке, которой нет. Автор также прав, утверждая что пакетный запрос выполнится гораздо быстрей, в разы и даже в порядки быстрей, поэтому эффективной замены ему нет.
но решение задачи есть. это создание хранимой процедуры. к сожалению MySQL не поддерживает создание временных процедур, поэтому алгоритм будет состоять из 4х отдельных запросов к серверу:
1. удаление процедуры на случай если она уже есть
DR OP PROCEDURE IF EXISTS myProc
2. создание процедуры
CRE ATE PROCEDURE myProc ()
BEGIN
UPD ATE tbl SE T name='один' WHERE id = '1';
UPDATE tbl SE T name='два' WHERE id = '2';
UPDATE tbl SE T name='три' WHERE id = '3';
...
END
3. вызов процедуры
CALL myProc
4. удаление процедуры
DR OP PROCEDURE IF EXISTS myProc
P.s. редактор поста за каким-то бесом портит код вставляя пробелы, надеюсь вы поймете где именно.
Решение выше не является оптимальным и верным.
С некоторой версии, по-моему с 5, можно выполнять пакеты запросов через ADODB для драйвера MySQL ODBC.
Для этого нужно в строке соединения указать параметр MULTI_STATEMENTS = 1;
Пример:
(19) ниже OerlandHue сделал замечание на счет параметра MULTI_STATEMENTS=1; которое я проверил и реально признаю, что так необходимость в создании процедуры отпала.