Выполнения пакета запросов в 1С++

Автор АЛьФ, 09 октября 2024, 12:32

« назад - далее »

АЛьФ

Решил опять попробовать разобраться почему не удаляются временные таблицы. Набросал такой вот запросик:
ТекстЗапроса = "
	|IF EXISTS(SELECT * FROM tempdb.dbo.sysobjects WHERE id = OBJECT_ID(N'[tempdb].[dbo].[#Временная]')) DROP TABLE #Временная
	|
	|SELECT ID
	|INTO #Временная
	|FROM Справочник_РегионыПрайса
	|
	|IF EXISTS(SELECT * FROM tempdb.dbo.sysobjects WHERE id = OBJECT_ID(N'[tempdb].[dbo].[#Временная]')) DROP TABLE #Временная
	|
	|SELECT DESCR
	|INTO #Временная
	|FROM Справочник_РегионыПрайса
	|
	|SELECT *
	|FROM #Временная
	|";
	
	тзВыборка = глПрямойЗапрос.ВыполнитьИнструкцию(ТекстЗапроса);

При попытке выполнить получаю ошибку:
There is already an object named '#Временная' in the database.

Отсюда сделал вывод, что SQL сначала создает временные таблицы, а потом их заполняет. И дроп посреди запроса похоже игнорируется, если таблица ранее уже встретилась.

В Menagement Studio проблема решается разбитием запроса с помощью "GO".
Как-то в 1С++ можно запрос разбить аналогичным образом? Или только вручную резать текст запроса на части?

trad


vladmenleo

Первой строкой в запросе поставить SET NOCOUNT ON не пробовали?

АЛьФ

Цитата: vladmenleo от 10 октября 2024, 12:51Первой строкой в запросе поставить SET NOCOUNT ON не пробовали?

Пробовали. Все та же ошибка "There is already..." еще на этапе до начала выполнения запроса.

vladmenleo

Есть еще нюанс. Если первое обращение вылетело с ошибкой, то временная таблица там останется, до какого времени не знаю, возможно до перезапуска сервера. Т.е. нужно сделать так: первая строка SET NOCOUNT ON, и заменить имя временной таблицы например на #ВременнаяНовая. Должно взлететь

АЛьФ

Цитата: vladmenleo от 10 октября 2024, 16:27Есть еще нюанс. Если первое обращение вылетело с ошибкой, то временная таблица там останется, до какого времени не знаю, возможно до перезапуска сервера. Т.е. нужно сделать так: первая строка SET NOCOUNT ON, и заменить имя временной таблицы например на #ВременнаяНовая. Должно взлететь
Именно на случай, если осталась временная таблица, в начале и стоит DROP. Но получается, что он не выполняется нормально. И NOCOUNT проблему не решает.
Мы вообще с этим начали разбираться из-за того, что иногда временная таблица создается в одном запросе (отчете), а потом в другом используется таблица с таким же именем, но другой структурой и получаем ошибку типа "нет такой колонки". Лечится перезаходом пользователя, но хотелось бы как-то проблему все же решить.

Arbuz

Как прямой вариант, добавить соль к имени таблицы.

trdm

Цитата: АЛьФ от 09 октября 2024, 12:32В Menagement Studio проблема решается разбитием запроса с помощью "GO".

в odbcrecordset (на скуле) разделитель запросов ";"
ТекстЗапроса = "
    |IF EXISTS(SELECT * FROM tempdb.dbo.sysobjects WHERE id = OBJECT_ID(N'[tempdb].[dbo].[#Временная]')) DROP TABLE #Временная
    |;
    |SELECT ID
    |INTO #Временная
    |FROM Справочник_РегионыПрайса
    |;
    |IF EXISTS(SELECT * FROM tempdb.dbo.sysobjects WHERE id = OBJECT_ID(N'[tempdb].[dbo].[#Временная]')) DROP TABLE #Временная
    |;
    |SELECT DESCR
    |INTO #Временная
    |FROM Справочник_РегионыПрайса
    |;
    |SELECT *
    |FROM #Временная
    |";
    
    тзВыборка = глПрямойЗапрос.ВыполнитьИнструкцию(ТекстЗапроса);

вот только запрос вернет последний результат.

АЛьФ

Цитата: trdm от 13 октября 2024, 23:20
Цитата: АЛьФ от 09 октября 2024, 12:32В Menagement Studio проблема решается разбитием запроса с помощью "GO".

в odbcrecordset (на скуле) разделитель запросов ";"
ТекстЗапроса = "
    |IF EXISTS(SELECT * FROM tempdb.dbo.sysobjects WHERE id = OBJECT_ID(N'[tempdb].[dbo].[#Временная]')) DROP TABLE #Временная
    |;
    |SELECT ID
    |INTO #Временная
    |FROM Справочник_РегионыПрайса
    |;
    |IF EXISTS(SELECT * FROM tempdb.dbo.sysobjects WHERE id = OBJECT_ID(N'[tempdb].[dbo].[#Временная]')) DROP TABLE #Временная
    |;
    |SELECT DESCR
    |INTO #Временная
    |FROM Справочник_РегионыПрайса
    |;
    |SELECT *
    |FROM #Временная
    |";
    
    тзВыборка = глПрямойЗапрос.ВыполнитьИнструкцию(ТекстЗапроса);

вот только запрос вернет последний результат.


Нет, все та же ошибка "There is already an object".

trdm

латиницу попробуй.
+ там имя не "#Временная" получается, а что-то вроде "#Временная        12121".
так что на равенство не особо надейся.
короче там все непросто. но победимо..

АЛьФ

Не понял по поводу латиницы. Ошибка "There is already an object" вываливается еще до начала выполнения собственно запроса. Я так понимаю, на этапе парсинга.

Вот для чистоты эксперимента код, который должен отработать на любой скульной базе:
ТекстЗапроса = "
	|SET NOCOUNT ON
	|
	|IF EXISTS(SELECT * FROM tempdb.dbo.sysobjects WHERE id = OBJECT_ID(N'[tempdb].[dbo].[#TMP]')) DROP TABLE #TMP
	|;
	|SELECT ID
	|INTO #TMP
	|FROM _1SCONST
	|;
	|IF EXISTS(SELECT * FROM tempdb.dbo.sysobjects WHERE id = OBJECT_ID(N'[tempdb].[dbo].[#TMP]')) DROP TABLE #TMP
	|;
	|SELECT DESCR, ID
	|INTO #TMP
	|FROM _1SCONST
	|;
	|SELECT *
	|FROM #TMP
	|";
	
	Запрос = СоздатьОбъект("ODBCRecordSet");
	тзВыборка = Запрос.ВыполнитьИнструкцию(ТекстЗапроса);

Получаем ошибку:
тзВыборка = Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
{...\TEST.ERT(22)}: State 42S01, native 2714, message [Microsoft][ODBC SQL Server Driver][SQL Server]There is already an object named '#TMP' in the database.

trad

Цитата: trdm от 13 октября 2024, 23:20в odbcrecordset (на скуле) разделитель запросов ";"
Нету там такого разделителя

Тут одно решение - резать выполнение на части

Djelf

Пожалуй соглашусь с #11, про mssql не уверен, но sqlite (а это я точно знаю) не умеет отслеживать предпологаемое изменение состава таблиц, т.е. каждый отдельный запрос в блоке запросов видит только первоначальное состояние таблиц, и не пытается понять динамику изменений внутри блока запросов.
Т.е. drop table и create table надо выносить за блоки запросов.

trdm

Цитата: trad от 15 октября 2024, 09:25Нету там такого разделителя
Верно, это в T-SQL он такой есть.


trdm

Цитата: АЛьФ от 14 октября 2024, 14:28Нет, все та же ошибка "There is already an object".

Верно, сори.
Дело в том, что я использовал консоль QA.ert, а там у меня есть обработка ";" и "GO", запросы делаются раздельно.
А если выполнять текст запроса так:
    Запрос = СоздатьОбъект("ODBCRecordSet");
    тзВыборка = Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
то ошибка та-же.