【问题标题】:Delete all tables by cursor(fetch table names) in SQL Server在 SQL Server 中通过游标(获取表名)删除所有表
【发布时间】:2019-04-01 06:55:11
【问题描述】:

我有一个带有stg_table 列的元数据表。这是dbo 模式中STAGE 数据库表的名称。当 insert_type 列是“选择”时,如果光标存在,我想删除表。

元数据示例:https://imgur.com/a/TfyIWpv

还有我的光标代码:

declare kursor cursor for 
     select * 
     from METADATA.dbo.META_SOURCESTAGE;

declare @insert_type varchar(15), 
        @stg_table varchar(30), 
        @src varchar(80), 
        @SQL varchar(254);

open kursor

fetch next from kursor into @insert_type, @stg_table, @src;

while @@FETCH_STATUS = 0
begin
    if @insert_type = 'select'
        begin
        select @SQL = 'IF OBJECT_ID('+@stg_table+') IS NOT NULL DROP TABLE '+@stg_table
    exec(@SQL)

    fetch next from kursor into @insert_type, @stg_table, @src;
    end
    if @insert_type = 'bulk'
        execute ('truncate table ' + @stg_table);

    print @stg_table;

    fetch next from kursor into @insert_type, @stg_table, @src;
end

close kursor;
deallocate kursor;

我想通过在 METADATA 表中创建的游标从 STAGE.dbo.* 中删除所有现有表。

我得到一个错误:

消息 4104,第 16 级,状态 1,第 2 行
无法绑定多部分标识符“STAGE.dbo.STG_KLIENT”。 STAGE.dbo.STG_MELDUNEK

消息 4104,第 16 级,状态 1,第 2 行
无法绑定多部分标识符“STAGE.dbo.STG_MIEJSCOWOSC”。
STAGE.dbo.STG_PRACOWNIK

@编辑 更改了代码 - 添加了开始/结束,但仍然出现相同的错误。

【问题讨论】:

  • 如果你想在IF之后执行多个语句,你必须使用一个BEGIN .... END块 - 否则只 下一条语句在 IF 部分内 - 在所有情况下都将执行除此之外的任何内容......

标签: sql sql-server tsql


【解决方案1】:

它抱怨无法绑定OBJECT_ID 调用,您的代码结果如下:

IF OBJECT_ID(STAGE.dbo.STG_KLIENT) IS NOT NULL DROP TABLE STAGE.dbo.STG_KLIENT

DROP TABLE 部分很好,但您需要在调用OBJECT_ID 时引用表名,因为它需要(N)VARCHAR 输入,所以请继续:

select @sql = 'IF OBJECT_ID('''+@stg_table+''') IS NOT NULL DROP TABLE '+@stg_table
--                           ^^            ^^

另外,你的代码有点乱。它会跳过一些表格,因为你正在做的是:

  1. 从光标中获取(第一个结果,假设选择类型)
  2. 检查@insert_type = 'select', true 所以让我们进入块
    • 删除表(如果存在)
    • 从游标中获取(第二个结果,让我们再次假设选择类型
    • 如果被阻止则离开
  3. 检查@insert_type = 'insert', false, 不要截断
  4. 打印表名
  5. 从光标中获取下一个 -> 第三个结果,你只是对第二个结果没有做任何你应该放弃它的地方。

这是一个稍微改进的版本:

while @@FETCH_STATUS = 0
begin
    if @insert_type = 'select'
    begin
       select @sql = 'IF OBJECT_ID('''+@stg_table+''') IS NOT NULL DROP TABLE '+@stg_table
    end
    else if @insert_type = 'insert'
    begin
       select @sql = 'TRUNCATE TABLE ' + @stg_table
    end

    print @sql -- "debugging"

    -- only do those once if you can, so you don't get lost in how the code branches
    exec sp_executesql @sql
    fetch next from kursor into @insert_type, @stg_table, @src;
end

此外,您实际上并不需要光标。您可以只生成一个大查询并执行一次。

DECLARE @sql NVARCHAR(MAX) = ''
SELECT @sql += CONCAT(CASE
                        WHEN meta.insert_table = 'select'
                         AND OBJECT_ID(meta.stg_table) IS NOT NULL
                        THEN CONCAT('DROP TABLE ', meta.stg_table)

                        WHEN meta.insert_table = 'insert'
                        THEN CONCAT('TRUNCATE TABLE', meta.stg_table)
                      END,
                      ';', CHAR(13), CHAR(10)) -- add newline for easier reading
  FROM METADATA.dbo.META_SOURCESTAGE meta

PRINT @sql
EXEC sp_executesql @sql

这应该可行,虽然我没有测试过,但我希望你能明白。

【讨论】:

    猜你喜欢
    • 2021-11-23
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 2011-04-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多