首次执行GO后,存储过程中的临时表不可用

时间:2015-11-16 01:40:43

标签: sql sql-server stored-procedures sql-server-2014

我需要运行140,000个INSERT语句。我试图将记录插入数据库表,然后将创建的PK输入临时表,然后返回。它看起来像这样:

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个插入语句,这种方式完美,但我认为由于这个特定SP中的语句数量,它给了我"查询完成错误&# 34;当我尝试创建程序时,但实际上并没有创建程序。

然后我每200个插入语句添加一个GO,但是在第一个GO执行后,必须释放临时表,并且我得到" TempTable不可用"错误(在第一次GO执行后,我也得到@PassInVariable的相同错误)。奇怪的是,当我将上述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;

5 个答案:

答案 0 :(得分:0)

Ben,这是一个常见的错误概念,即" GO"在SQLServer中。 " GO"它不是T-SQL的一部分,它是SQLServer工具(ssms,sqlcmd,sqlwb,isql和其他)的指令,用于在不同的语句中拆分脚本。 所以你不能在SP和函数中使用它(甚至在动态SQL中),只能在脚本中使用它。

虽然我不明白为什么你的SP无法创建,但如果你想从Java,.NET,你需要添加的其他平台运行你的程序

SET NOCOUNT ON

答案 1 :(得分:0)

  

TempTable不可用

您收到此错误是因为本地临时表仅对创建它的连接可见,并在关闭该连接时被删除。在存储过程中使用GO结束批处理,从而结束存储过程。

解决方案是使用单个INSERT查询并使用OUTPUT子句存储新插入的IDs

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

将来自ID的{​​{1}}替换为来自INSERTED.ID的正确ID

要多次插入行,您可以使用Tally Table

MyDBTable

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 替换为您要插入的行数。

Here is a simplified explanation of Tally Table.

答案 2 :(得分:0)

MS SQL中的GO语句释放资源并清理会话;这就是临时表和变量一样消失的原因。

在您的存储过程中或至少上面的SQL脚本中,您不需要go语句。

您在其他脚本中看到的GO语句是为了防止解析器在前一个语句出错后停止执行。它类似于Visual Basic" On Error Resume Next"声明。这样你的脚本将继续执行,直到脚本文件结束。

您将看到GO语句主要用于包含多个事务的脚本文件中;每次交易后都是一个go语句。例如,包含用于不同存储过程的多个CREATE语句的脚本文件。但是在一次交易中,您不想使用GO语句,因为您将在脚本中看到所有变量(包括临时表)。

我不会在你的存储过程中看到需要。

答案 3 :(得分: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更好,通常是推荐的方法。

答案 4 :(得分:0)

谢谢大家的答案......我最终得到了以下解决方案:

从调用我的存储过程的脚本中创建了#TempTable

numpy.save

然后在我的存储过程中,我有:

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

我在大约每100个select语句之后重复INSERT / OUTPUT行,并且整个事情成功地运行得非常快!