SQL游标使用Temp Table中的表和字段名称

Ric*_*ner 5 sql sql-server cursor

我将通过让大家知道我几年前曾答应自己永远不会在不需要的SQL中使用游标来开头.不幸的是,我认为我可能不得不在目前的情况下使用一个,但是很长时间以来我都在努力记住正确的语法.

基本上,我CONVERT_IMPLICIT在查询中遇到了问题,因为我的数据类型对于不同表中的相同字段是不同的,所以我想最终将它们转换为int.但要做到这一点,我需要检查是否所有数据都可以转换为int,以查看作业有多大.

我在下面的查询中给出了一个包含列表中相关字段的数据库中所有表的列表;

IF OBJECT_ID('tempdb..#BaseData') IS NOT NULL DROP TABLE #BaseData
GO
CREATE TABLE #BaseData (Table_Name varchar(100), Field_Name varchar(100), Data_Type_Desc varchar(20), Data_Max_Length int, Convertible bit)

DECLARE @FieldName varchar(20); SET @FieldName = 'TestFieldName'

INSERT INTO #BaseData (Table_Name, Field_Name, Data_Type_Desc, Data_Max_Length)
SELECT
o.name ,c.name ,t.name ,t.max_length 
FROM sys.columns c
JOIN sys.types t
    ON c.user_type_id = t.user_type_id
JOIN sys.objects o
    ON c.object_id = o.object_id
WHERE c.name LIKE '%' + @FieldName + '%'
    AND o.type_desc = 'USER_TABLE'
Run Code Online (Sandbox Code Playgroud)

这给出了这样的结果;

Table_Name  Field_Name      Data_Type_Desc  Data_Max_Length Convertible
Table1      TestFieldName   varchar         8000            NULL
Table2      TestFieldName   nvarchar        8000            NULL
Table3      TestFieldName   int             4               NULL
Table4      TestFieldName   varchar         8000            NULL
Table5      TestFieldName   varchar         8000            NULL
Run Code Online (Sandbox Code Playgroud)

我想做的是检查相关表和字段中的所有数据是否都可以转换为int并更新'convertible'字段(如果有无法转换的数据则为1,如果数据正常则为0) ).我有以下计算,它完美无缺;

'SELECT  
CASE 
    WHEN COUNT(' + @FieldName + ') - SUM(ISNUMERIC(' + @FieldName + ')) > 0 
        THEN 1 
    ELSE 0 
END 
FROM ' + @TableName
Run Code Online (Sandbox Code Playgroud)

并给出了我追求的结果.但是我很难找到正确的语法来创建游标,它将查看临时表中的每一行并相应地运行此SQL.然后,它需要使用查询结果(1或0)更新临时表的最后一列.

这将必须在几百个数据库上运行,这就是为什么我需要这个列表是动态的,在某些数据库中可能有自定义表(事实上,它很可能).

如果有人能提供任何指导,我们将不胜感激.

谢谢

SMM*_*SMM 3

我对您的原始查询做了一些更改,但这应该可行。我过去也做过类似的事情:-)

变化:

  • 将架构添加到源表 - 我的测试数据库在多个架构中具有匹配项
  • 将数据类型更改为 sysname、smallint 以匹配表定义,否则名称可能会被截断

    IF OBJECT_ID('tempdb..#BaseData') IS NOT NULL DROP TABLE #BaseData;
    GO
    
    CREATE TABLE #BaseData (Schema_Name sysname, Table_Name sysname, Field_Name sysname, Data_Type_Desc sysname, Data_Max_Length smallint, Convertible bit);
    
    DECLARE @FieldName varchar(20); SET @FieldName = 'TestFieldName';
    
    INSERT INTO #BaseData (Schema_Name, Table_Name, Field_Name, Data_Type_Desc, Data_Max_Length)
    SELECT
    s.name, o.name ,c.name ,t.name ,t.max_length 
    FROM sys.columns c
    JOIN sys.types t
        ON c.user_type_id = t.user_type_id
    JOIN sys.objects o
        ON c.object_id = o.object_id
    JOIN sys.schemas s ON o.schema_id=s.schema_id
    WHERE c.name LIKE '%' + @FieldName + '%'
        AND o.type_desc = 'USER_TABLE';
    
    --select * from #BaseData;
    
    DECLARE @sName sysname,
            @tName sysname,
            @fName sysname,
            @sql VARCHAR(MAX);
    
    DECLARE c CURSOR LOCAL FAST_FORWARD FOR
        SELECT  Schema_Name,
                Table_Name,
                Field_Name
        FROM #BaseData;
    OPEN c;
    FETCH NEXT FROM c INTO @sName, @tName, @fName;
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
    SET @sql = 'UPDATE #BaseData SET Convertible =   
                    (SELECT 
                    CASE 
                        WHEN COUNT(' + @fName + ') - SUM(ISNUMERIC(' + @fName + ')) > 0 
                            THEN 1 
                        ELSE 0
                    END Convertible
                    FROM ' + @sName + '.' + @tName + ')
                FROM #BaseData WHERE Schema_Name = ''' + @sName + ''' AND Table_Name = ''' + @tName + ''' AND Field_Name = ''' + @fName + '''';
    
    --select @sql;
    EXEC(@sql); 
    
    FETCH NEXT FROM c INTO @sName, @tName, @fName;
    END
    
    CLOSE c;
    DEALLOCATE c;
    
    select *
    from #BaseData;
    
    Run Code Online (Sandbox Code Playgroud)