带有表变量的动态查询以循环遍历所有表以在数据库中更新

Posted

技术标签:

【中文标题】带有表变量的动态查询以循环遍历所有表以在数据库中更新【英文标题】:Dynamic query with table variable to loop through all tables to update in a database 【发布时间】:2019-03-07 17:13:34 【问题描述】:

我正在处理 SQL 查询以更新数据库中的表和列列表。欢迎提出任何建议。

我正在使用 information_schema.tables 和 information_schema.columns、查找表和一个表变量。但是,我在更新时遇到了问题。

我从连接开始,以确保我匹配查找表所需的正确表和列。

如果 table.column,我需要循环并更新与对象名匹配的表。

我尝试使用游标,但做了一些研究并认为表变量可能更适合优化和性能。 我声明了我的变量并创建了一个表变量,但它仍然没有更新。在创建并填充表变量后,我开始使用以下查询。

我用游标和表变量尝试了不同的方法,但我没有正确完成更新。

'Select l.objectname, l.fieldname, l.newpvalue, l.oldpvalue from lookup_table 1 inner join information_schema.tables t
                 on l.objectname = t.table_name
                inner join information_schema.columns c
                  on l.fieldname = c.column_name and l.objectname 
                                 = c.table_name'

这是我尝试参数化的新更新

SELECT 'UPDATE' + I.TABLE_NAME + 'SET C.COLUMN_NAME = 
                                        CASE 
                                            WHEN TP.[listValue] = TP.[OldValue]
                                            WHEN TP.[listValue] != TP.[OldValue] 
                                                        THEN SET TP.NOTES = C.COLUMN_NAME '-' TP.[OldValue]
                                                        AND SET C.COLUMN_NAME = NULL
                                        END
        FROM 
                INFORMATION_SCHEMA.TABLES I INNER JOIN [dbo].[tpRef] tp
                                    ON I.TABLE_NAME = tp.ObjectName
                                INNER JOIN INFORMATION_SCHEMA.COLUMNS C
                                    ON tp.[FieldName] = C.COLUMN_NAME
                                        AND tp.[ObjectName] = C.TABLE_NAME
                                LEFT JOIN INFORMATION_SCHEMA.COLUMNS C2
                                    ON tp.[FieldName] = C2.COLUMN_NAME
                                    AND C2.COLUMN_NAME = 'NOTES'
        WHERE TABLE_TYPE = 'base table'
                        AND tp.ObjectName = 'table name'
                        AND tp.FieldName = 'table field'
                        AND tp.[listValue] = 'List' 

【问题讨论】:

你是说我应该使用带有表变量的游标吗? 【参考方案1】:

不是工作游标,需要查询来填写所需的列来填充变量。

declare 
     @table_name varchar(128) 
    ,@schema_name varchar(128) -- dbo is the default schema, if custom make sure query returns the correct schema
    ,@update_column varchar(128) 
    ,@update_data varchar(1024)
    ,@where_column varchar(128)
    ,@where_data varchar(1024)
    ,@s varchar(max);
declare x cursor local fast_forward 
for
/*
 insert your query returning desired values to be looped through.
 */
select 1,2,3,4,5,6 --6 variables to populate. delete this line when you get your query written above :)
open x;
fetch next from x into @table_name,@update_column,@schema_name,@update_data,@where_column,@where_data;

while @@fetch_status = 0
    begin
        set @s = '
            update ' + quotename(@schema_name) + '.' + quotename(@table_name) + ' 
            set  ' + quotename(@update_column) + ' = ''' + @update_data + ''' where ' + quotename(@where_column) + ' = ''' + @where_data + ''';
            '
        begin try
            --to execute it, you can use exec()
            exec(@s); 
            --to print out the string so you can read and or copy/paste to text execution use print()
            print(@s);
            /* 
                I would recommend print(@s); until you have all your bugs worked out.
                process the updates manually from the printed statements to verify syntax correctness and results
             */
        end try
        begin catch
            print error_message()
        end catch;
        -- this list of variables must match the first "fetch next" and all be declared and returned in the "for" query of the cursor.
        -- those that are not must be set inside the cursor by queries, calculations or hardcoded.
        fetch next from x into @table_name,@update_column,@schema_name,@update_data,@where_column,@where_data;
    end

close x;
deallocate x;

使用的光标是Fast_forward(SO answer) = (read_only and forward_only) Local(游标性能细分) = 范围内的本地,仅在范围内有效。

我仍然无法使用 information_schema 视图...

【讨论】:

谢谢,但我需要更新表和列数据值。我正在使用查找来传递我需要比较以确定值更新的表名、列名和值。我将删除您正在提取的我不需要的信息并尝试使用此信息。我正在使用我正在使用的动态 sql 获取语法。 我遇到的问题是在需要传递表名和列名的集合查询中执行更新语句 修改了答案,使其更接近您的最终结果需要,仍然需要使用返回更新所需数据的查询填充游标。 谢谢我确实做了你昨天修改的内容。它正在更新,但值不正确。所以我今天早上再次测试,但它现在根本没有更新,所以跟踪看看有什么变化。【参考方案2】:

我试图使用表变量,但您是否指示同时使用表变量和游标?

当我运行以下是需要很长时间。

----找到更新表和列

SELECT @STRUPDSQL =
         'UPDATE' + 'I.TABLE_NAME' + 'SET C.COLUMN_NAME = 
                                        CASE 
                                            WHEN TP.[PicklistValue] = TP.[OldValue]
                                            WHEN TP.[PicklistValue] != TP.[OldValue] 
                                                        THEN SET TP.NOTES = C.COLUMN_NAME - TP.[OldValue]
                                                        AND SET C.COLUMN_NAME = NULL
                                        END
        FROM 
                INFORMATION_SCHEMA.TABLES I INNER JOIN @TBLS T
                                            ON I.TABLE_NAME = T.v_TABLENAME

        WHERE T.v_TABLENAME =@l_TBLNM   AND T.v_COLUMNNAME =@l_COLNNM                   

'
    SET @I = @I + 1
    END

我让它工作了,但是我想要更新的值被读取为列名,而不是列数据值。

如果引号名称(@COLNAME)不为空

        BEGIN
            SET @SQL = 'UPDATE ' + quotename(@TABLENAME) + ' SET ' + quotename(@COLNAME) + ' = ' +'"' + @TVALUE + '"' + ' ' + 'WHERE ' + quotename(@COLNAME) + '= AccountSource'
        END

【讨论】:

我意识到我需要返回包含一个临时表或表变量,就像我在原始代码中所做的那样,才能成功更新我正在传递的表中的值。

以上是关于带有表变量的动态查询以循环遍历所有表以在数据库中更新的主要内容,如果未能解决你的问题,请参考以下文章

如何有效地查询多个表以在 dataGrid 中生成 excel STYLE 报告

删除所有表以在 Django 中运行 syncdb 的最简单方法?

Oracle - 匿名过程循环遍历多个表(动态) - 查询返回多行

动态变量名称以在 for 循环中改变变量

在 SPSS 中,如何通过标签变量循环遍历自变量来进行一堆回归分析?在 R 中更容易吗? [复制]

如何过滤我的表以在 Oracle 中显示结果?