2015-11-16 2 views
0

У меня есть 140 000 инструкций INSERT Мне нужно запустить. Я пытаюсь вставить запись в таблицу базы данных, а затем ввести созданные PK в временную таблицу, которую я затем верну. Это выглядит примерно так:Таблица Temp хранимой процедуры недоступна после первого GO

CREATE PROCEDURE sp_MassInsertProcedure 
    @PassInVariable int 
AS 
    CREATE TABLE #TempTable(OriginalID int IDENTITY(1,1), NewID int); 

    --These two inserts are essentially repeated 70,000 times 
    INSERT INTO MyDBTable (something, something, something) VALUES (1, 2, @PassInVariable); 
    INSERT INTO #TempTable(NewID) SELECT SCOPE_IDENTITY(); 

    SELECT * FROM #TempTable; 
    DROP TABLE #TempTable; 

У меня есть несколько других хранимых процедур так же, как это, которые имеют максимум 2000 операторов вставки и так отлично работает, но я думаю, что из-за количество заявлений в данном СП он дает мне «Запрос завершен с ошибками», когда я пытаюсь создать процедуру, но на самом деле не создаю процедуру.

Затем я добавил GO каждые 200 операторов вставки, но после первого запуска GO будет выпущена временная таблица, и я получаю сообщение об ошибке «TempTable is unavailable» (я также получаю ту же ошибку для @PassInVariable после первого GO выполняет). Странным является то, что когда я помещаю выше описанный SQL в стандартный скрипт (не в хранимую процедуру), он работает.

Итак, мой вопрос: кто-нибудь знает, как сохранить временную таблицу/переменную в одной хранимой процедуре, которая использует несколько пакетных исполнений с помощью команды GO?

CREATE PROCEDURE sp_MassInsertProcedure 
    @PassInVariable int 
AS 
    CREATE TABLE #TempTable(OriginalID int IDENTITY(1,1), NewID int); 

    --These inserts are essentially repeated 70,000 times 
    INSERT INTO MyDBTable (something, something, something) VALUES (1, 2, @PassInVariable); 
    INSERT INTO #TempTable(NewID) SELECT SCOPE_IDENTITY(); 
    GO 
    INSERT INTO MyDBTable (something, something, something) (1, 2, @PassInVariable); 
    INSERT INTO #TempTable(NewID) SELECT SCOPE_IDENTITY(); 

    SELECT * FROM #TempTable; 
    DROP TABLE #TempTable; 
+1

Вы приближаетесь к проблеме с неправильным решением. Вы можете сделать это, используя один запрос с использованием предложения 'OUTPUT' –

ответ

0

Спасибо всем за ответы ... Я в конечном итоге следующим раствором:

Из сценария, который звонил мой хранимой процедуры я создал #TempTable

CREATE TABLE #TempTable (OriginalID int IDENTITY(1,1), NewID int); 
EXEC sp_InsertMassRecords 777; 

, а затем в моя хранимая процедура у меня была:

CREATE PROCEDURE sp_InsertMassRecords 
    @IncomingVariable int 
AS 
BEGIN 
    SET NOCOUNT ON; 

    INSERT MyDBTable (col1, col2, col3) 
    OUTPUT Inserted.ID INTO #TempTable(NewID) 
    SELECT 1, @IncomingVariable, 3 UNION ALL 
    SELECT 4, @IncomingVariable, 6 UNION ALL... 

Я повторил INSERT/OUTPUT строки после примерно каждые 100 отборных заявлений или так и го Все это прошло успешно довольно быстро!

0

Бен, это распространенное заблуждение относительно «GO» в SQLServer. «GO» не является частью T-SQL, это директива для инструментов SQLServer (ssms, sqlcmd, sqlwb, isql и др.) Для разделения скриптов в разных операторах. Таким образом, вы не можете использовать его в SP и функциях (даже в динамическом SQL), только в скриптах.

Хотя я не понимаю, почему ваш SP не может быть создана, но если вы хотите, чтобы запустить процедуру с Java, .NET, другие платформы, вам нужно добавить

SET NOCOUNT ON 
0

TempTable недоступен

Вы получаете эту ошибку, поскольку локальная временная таблица видна только подключению, которое ее создает, и удаляется при закрытии этого соединения. Использование GO внутри хранимой процедуры завершает пакет и, следовательно, хранимую процедуру.

Решение состоит в том, чтобы использовать один INSERT запрос и использовать предложение OUTPUT для хранения вновь вставляется IDs:

INSERT INTO MyDBTable (something, something, something) 
OUTPUT Inserted.ID INTO #TempTable(NewID) 
VALUES (1, 2, @PassInVariable); 

Заменить ID из INSERTED.ID с правильным ID от MyDBTable


Чтобы вставить строку несколько раз, вы можете использовать Tally Table :

WITH E1(N) AS(
    SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) t(N) 
), 
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), 
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), 
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b), 
Tally(N) AS(
    SELECT TOP(70000) 
     ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) 
    FROM E8 
) 
INSERT INTO MyDBTable(something, something, something) 
OUTPUT Inserted.ID INTO #TempTable(NewID) 
SELECT 
    1, 2, @PassInVariable 
FROM Tally 

Заменить TOP с количеством строк, которые вы хотите вставить.

Here is a simplified explanation of Tally Table.

0

Оператор GO в MS SQL высвобождает ресурсы и очистить вашу сессию; поэтому таблица temp также исчезла из ваших переменных.

В вашем сохраненном proc или, по крайней мере, SQL-скрипте выше вам не требуется инструкция go.

Операторы GO, которые вы видите в других сценариях, должны помешать синтаксическому анализатору прекратить выполнение после ошибок предыдущих операторов. он похож на оператор Visual Basic «On Error Resume Next». таким образом ваш скрипт будет продолжать выполнение до конца файла сценария.

Вы увидите, что оператор GO будет использоваться в основном в файле сценария, который содержит несколько транзакций; после каждой транзакции - инструкция go. Например, файл сценария, который содержит несколько инструкций CREATE для разных процедур хранения. Но в течение одной транзакции вы не хотите использовать оператор GO, потому что вы потеряете все свои переменные (включая временную таблицу (таблицы)), как вы видите в своем скрипте.

Я не вижу необходимости в вашей сохраненной программе, хотя.

+0

Итак, я удалил GO и просто упростил свой SP, поэтому он передает параметр, а затем выполняет 70 000 вставных операторов ... .После того, как «Запрос завершен с ошибками», но нет сообщения. Я подозрительно, что это просто связано с массовым количеством вставок, но не может подтвердить ... пытаться посмотреть, как получить дополнительную информацию. –

+0

Я не использовал функцию SCOPE_IDENTITY(); Я использую только параметр @@ IDENTITY, чтобы получить новое добавленное значение Identity. Почему бы вам не попробовать? – NPToita

+0

Феликс Памиттан, ответ, может быть, интересный и заслуживающий внимания. – NPToita

0

Причина, временная таблица не доступен, потому что хранимая процедура:

CREATE PROCEDURE sp_MassInsertProcedure 
    @PassInVariable int 
AS 
    CREATE TABLE #TempTable(OriginalID int IDENTITY(1,1), NewID int); 

    --These inserts are essentially repeated 70,000 times 
    INSERT INTO MyDBTable (something, something, something) VALUES (1, 2, @PassInVariable); 
    INSERT INTO #TempTable(NewID) SELECT SCOPE_IDENTITY(); 
    GO 

Определение останавливается на GO, по причинам, изложенным в других ответах.

Теперь несколько полезных советов:

  • Положите тело хранимой процедуры в BEGIN/END блоков или BEGIN CATCH/END TRY блоков. Тогда нет никакой двусмысленности в отношении того, где это происходит или заканчивается.
  • Вам не нужно удалять временную таблицу в конце хранимой процедуры. Это происходит автоматически. Однако я признаю, что лично предпочитаю переменные таблицы, потому что более очевидно, что они удалены.
  • Лучший способ получить возвращаемые значения - использовать предложение OUTPUT. SCOPE_IDENTITY() довольно безопасно. Но OUTPUT лучше и, как правило, рекомендуется.
Смежные вопросы