У меня есть три хранимых процедуры Sp1
, Sp2
и Sp3
.
Первый ( Sp1
) выполнит второй ( Sp2
) и сохранит возвращенные данные, @tempTB1
а второй выполнит третий ( Sp3
) и сохранит данные в @tempTB2
.
Если я выполню, Sp2
он будет работать, и он вернет мне все мои данные из Sp3
, но проблема в том Sp1
, что когда я его выполню, он отобразит эту ошибку:
Оператор INSERT EXEC не может быть вложенным
Я попытался изменить место, execute Sp2
и он показал мне еще одну ошибку:
Невозможно использовать инструкцию ROLLBACK в инструкции INSERT-EXEC.
sp_help_jobactivity
).Это единственный «простой» способ сделать это в SQL Server без какой-либо гигантской запутанной созданной функции или выполненного вызова строки sql, оба из которых являются ужасными решениями:
ПРИМЕР:
Примечание : вы ДОЛЖНЫ использовать 'set fmtonly off', И вы НЕ МОЖЕТЕ добавить к нему динамический sql ни внутри вызова openrowset, ни для строки, содержащей параметры вашей хранимой процедуры, ни для имени таблицы. Вот почему вам нужно использовать временную таблицу, а не табличные переменные, что было бы лучше, поскольку в большинстве случаев она выполняет временную таблицу.
источник
Хорошо, поощряемый jimhark, вот пример старого подхода с использованием единой хеш-таблицы:
источник
Моя работа для решения этой проблемы всегда заключалась в использовании принципа, согласно которому отдельные временные хеш-таблицы входят в область действия любых вызываемых процессов. Итак, у меня есть переключатель опций в параметрах процесса (по умолчанию выключено). Если это включено, вызываемая процедура вставляет результаты во временную таблицу, созданную в вызывающей процедуре. Я думаю, что в прошлом я сделал еще один шаг и поместил некоторый код в вызываемую процедуру, чтобы проверить, существует ли единая хеш-таблица в области видимости, если она есть, затем вставьте код, иначе верните набор результатов. Кажется, работает хорошо - лучший способ передачи больших наборов данных между процессами.
источник
У меня этот трюк работает.
У вас нет этой проблемы на удаленном сервере, потому что на удаленном сервере последняя команда вставки ожидает выполнения результата предыдущей команды. На одном сервере это не так.
Воспользуйтесь этой ситуацией для обходного пути.
Если у вас есть право на создание связанного сервера, сделайте это. Создайте тот же сервер, что и связанный сервер.
теперь ваша команда Sql в SP1
Поверьте, работает даже у вас есть динамическая вставка в SP2
источник
Я нашел решение - преобразовать одно из запросов в функцию с табличным значением. Я понимаю, что это не всегда возможно, и вводит свои ограничения. Однако мне всегда удавалось найти хотя бы одну из процедур, подходящую для этого. Мне нравится это решение, потому что оно не вносит никаких "взломов" в решение.
источник
Я столкнулся с этой проблемой при попытке импортировать результаты хранимой процедуры во временную таблицу, и что хранимая процедура вставлена во временную таблицу как часть своей собственной операции. Проблема в том, что SQL Server не позволяет одному и тому же процессу одновременно записывать в две разные временные таблицы.
Принятый ответ OPENROWSET работает нормально, но мне нужно было избегать использования динамического SQL или внешнего поставщика OLE в моем процессе, поэтому я пошел другим путем.
Я нашел один простой обходной путь - заменить временную таблицу в моей хранимой процедуре табличной переменной. Он работает точно так же, как и с временной таблицей, но больше не конфликтует с моей другой вставкой временной таблицы.
Просто чтобы избежать комментария, я знаю, что некоторые из вас собираются написать, предупреждая меня об использовании табличных переменных как убийц производительности ... Все, что я могу вам сказать, это то, что в 2020 году не бояться табличных переменных выгодно. Если бы это был 2008 год, и моя база данных размещалась на сервере с 16 ГБ ОЗУ и с жесткими дисками 5400 об / мин, я мог бы согласиться с вами. Но сейчас 2020 год, и у меня есть SSD-массив в качестве основного хранилища и сотни гигабайт оперативной памяти. Я мог бы загрузить всю базу данных моей компании в табличную переменную и при этом иметь достаточно свободной оперативной памяти.
Табличные переменные снова в меню!
источник
У меня была такая же проблема и беспокойство по поводу дублирования кода в двух или более sprocs. В итоге я добавил дополнительный атрибут для «режима». Это позволяло существовать общему коду внутри одного sproc и потока, направленного в режим, и набора результатов sproc.
источник
как насчет того, чтобы просто сохранить вывод в статической таблице? подобно
это не идеально, но это так просто, и вам не нужно все переписывать.
ОБНОВЛЕНИЕ : предыдущее решение не работает с параллельными запросами (асинхронный и многопользовательский доступ), поэтому теперь я использую временные таблицы
spGetData
содержимое вложенных хранимых процедуристочник
Объявите переменную курсора вывода для внутреннего sp:
Затем объявите курсор c для выбора, который вы хотите вернуть. Затем откройте курсор. Затем установите ссылку:
НЕ закрывайте и не перераспределяйте.
Теперь вызовите внутренний sp из внешнего, задав параметр курсора, например:
Как только внутренний sp выполняется, ваш
@cOUT
готов к загрузке. Зациклить, а затем закрыть и освободить.источник
Если вы можете использовать другие связанные технологии, такие как C #, я предлагаю использовать встроенную команду SQL с параметром Transaction.
Я создал простое консольное приложение, демонстрирующее эту способность, которое можно найти здесь: https://github.com/hecked12/SQL-Transaction-Using-C-Sharp
Короче говоря, C # позволяет преодолеть это ограничение, когда вы можете проверять вывод каждой хранимой процедуры и использовать этот вывод, как вам нравится, например, вы можете передать его другой хранимой процедуре. Если результат в порядке, вы можете зафиксировать транзакцию, в противном случае вы можете отменить изменения с помощью отката.
источник
В SQL Server 2008 R2 у меня было несоответствие в столбцах таблицы, которое вызывало ошибку отката. Это исчезло, когда я исправил мою табличную переменную sqlcmd, заполненную оператором insert-exec, чтобы она соответствовала той, которая возвращалась сохраненной процедурой. Отсутствовал org_code. В файле cmd Windows он загружает результат хранимой процедуры и выбирает его.
источник