【问题标题】:create/alter procedure with if object_id is not null then drop?如果 object_id 不为空,则创建/更改过程然后丢弃?
【发布时间】:2012-06-05 13:58:09
【问题描述】:

我希望程序首先检查临时表是否已经存在。如果确实如此,则删除表格并继续选择表格。但是我收到了这个错误:

'CREATE/ALTER PROCEDURE' must be the first statement in a query batch.

我的代码如下所示:

GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[GetData]
    @Param_Id int
AS
BEGIN

If OBJECT_ID('temp_table') is not null
drop table temp_table

select data_info into temp_table
from data_info_table1

END

但我不断收到同样的错误。有什么建议吗?

【问题讨论】:

  • 看不出为什么该代码会导致该错误。这就是您在查询窗口中的所有代码吗?
  • 基本上,是的.. 我有三个 select into 命令,仅此而已.. 我只需要确保表不存在..
  • 嗯,错误消息是抱怨“CREATE/ALTER PROCEDURE”必须是查询批处理中的第一条语句。不知道为什么您认为这与您发布的存储过程中的代码有关。

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


【解决方案1】:

您是否希望程序对 Null 进行 ansi 处理?尝试在过程中设置您的 Set Ansi Null On。

此外,如果您手动执行此操作,您可以先更改选项,方法是仅选择该代码并运行它,然后仅选择存储过程并单独运行它。

【讨论】:

    【解决方案2】:

    当脚本如下所示时,我收到相同的错误消息。这意味着缺少GO 语句。

    if Exists(select object_id from sys.objects where name = 'GetData' and type = 'p')
    Begin
        Drop Proc GetData
    End
    GO --Missing part
    CREATE PROCEDURE [dbo].[GetData]
    @Param_Id int
    AS
    BEGIN
        If OBJECT_ID('temp_table') is not null
           drop table temp_table
    
        select data_info into temp_table from data_info_table1
    END
    

    【讨论】:

      【解决方案3】:

      GO 命令表示一批 T-SQL 语句的结束。 GO 命令之后的任何语句都表示新一批查询或 T-SQL 语句的开始。因此,我建议您删除开头的 GO 命令并保留 CREATE 语句之前的命令,因此它现在成为后续查询批处理中的第一个语句。

      语句如下所示

      SET ANSI_NULLS ON
      
      SET QUOTED_IDENTIFIER ON
      
      GO
      CREATE PROCEDURE [dbo].[GetData] @Param_Id int
      AS
      BEGIN
      
      If OBJECT_ID('temp_table') IS NOT NULL DROP table temp_table
      
      SELECT data_info INTO temp_table FROM data_info_table1
      
      END
      GO
      

      【讨论】:

        【解决方案4】:

        您不想因为您在数据库中使用永久结构而造成 2 个不同的用户丢失他们的数据的可能性,对吗?如果您创建静态表会发生什么。然后它实际上非常简单。如果您使用会话临时表(名称看起来像 #temp_table),则需要在 tempdb 数据库中查找这些内容:

        IF OBJECT_ID('tempdb..#temp_table') IS NOT NULL
        

        这样做只是一种预防措施,因为名称以 # 开头的表会在查询完成后被删除,并且这些表是特定于查询的,这意味着它不会干扰其他用户或请求的并行连接。你的整个脚本应该是这样的:

        GO
        If OBJECT_ID('GetData') is not null
              drop PROCEDURE GetData
        GO
        SET ANSI_NULLS ON
        GO
        SET QUOTED_IDENTIFIER ON
        GO
        
        CREATE PROCEDURE [dbo].[GetData]
            @Param_Id int
        AS
        BEGIN
        
           If OBJECT_ID('tempdb..#temp_table') is not null
                drop table #temp_table
        
           select data_info into #temp_table
           from data_info_table1
        
            -- do what ever you need to do here with you data and spit it out to user.
        END
        GO
        

        【讨论】:

          【解决方案5】:

          尝试将 GO 放在 DROP TABLE 之后。我发现 IF OBJECT_ID() 不是 NULL 删除表 ** 本身并不总是有效,但在它之后使用 GO 似乎是可靠的: 如果 OBJECT_ID() 不是 NULL 删除表 ** 去吧

          【讨论】:

            【解决方案6】:

            存在编译器错误。 如果你真的想创建这个过程并且表 temp_table 是真正的 tamp 表,你可以在创建过程之前尝试删除它。 像这样:

            If OBJECT_ID('temp_table') is not null
            drop table temp_table
            go
            
            create PROCEDURE [dbo].[GetData]
                @Param_Id int
            AS
            BEGIN
            
            If OBJECT_ID('temp_table') is not null
            drop table temp_table
            
            select data_info into temp_table
            from data_info_table1
            
            END
            

            或真正使用临时表,如#table、##table 或@table

            【讨论】:

              【解决方案7】:

              如果你用这个改变你的存储过程呢?:

              CREATE PROCEDURE [dbo].[GetData]
                  @Param_Id int
              AS
              BEGIN
              
              If EXISTS(SELECT * FROM sys.tables WHERE name = 'temp_table')
              BEGIN
                  drop table temp_table
              END
              
              DECLARE @SQL VARCHAR(1000)
              SET @SQL = '
              select data_info into temp_table
              from data_info_table1'
              
              EXEC(@SQL)
              
              END
              

              【讨论】:

              • 试过了。但得到:数据库中已经有一个名为“temp_table”的对象。
              • @user1129988 - 基本上,sp 没有意识到您正在验证表的存在,如果它在INTO 之前已经存在,则将其删除,因此它告诉您这是重复的。尝试将其包装在动态查询中,它应该可以正常工作。我更新了我的答案。
              • 这是一种有效的方法吗.. 因为我没有一个选择“进入”我有三个
              • @user1129988 - 与使用INTO 创建表一样有效。我不是在谈论将您的整个 sp 放在动态查询上,只是您的 INTO 语句。
              • @user1129988 - 不,因为引擎无法识别表已被删除,就像您现在一样。因此,您要么动态执行INTO,要么不一遍又一遍地删除和创建表,而是执行DELETEINSERT INTO
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-02-16
              • 2013-05-26
              • 1970-01-01
              • 1970-01-01
              • 2017-09-28
              • 2012-05-25
              • 2021-09-20
              相关资源
              最近更新 更多