【问题标题】:Loop through multiple Float columns in a DB using Dynamic SQL使用动态 SQL 循环遍历数据库中的多个 Float 列
【发布时间】:2019-01-15 16:15:34
【问题描述】:

如何遍历数据库中不同表的多个列?我通过一次查询一列来找到我需要的结果,这需要很多时间。

SELECT MAX
       (CASE Charindex('.', COLUMN1)
                    WHEN 0 THEN 0
                    ELSE
   Len (Cast(Cast(Reverse(CONVERT(VARCHAR(50), COLUMN1, 128)
                     ) AS FLOAT) AS BIGINT))
                  END) AS MAX_LENGTH
FROM   DB1.dbo.TABLE1

我的代码在这里,但它不起作用,因为我发送了多个值

DECLARE @cols NVARCHAR(MAX)
    ,@sql NVARCHAR(MAX)

SET @cols = (SELECT quotename(COLUMN_NAME) FROM BRSDATA.INFORMATION_SCHEMA.COLUMNS A
inner join BRSDATA.INFORMATION_SCHEMA.TABLES B
on A.TABLE_NAME = B.TABLE_NAME
where TABLE_TYPE = 'BASE TABLE'
and DATA_TYPE = 'Float')

Set @sql =  'SELECT MAX(CASE Charindex(''.'',' + @cols + ')
                    WHEN 0 THEN 0
                    ELSE
   Len (Cast(Cast(Reverse(CONVERT(VARCHAR(50), ' + @cols + ', 128)
                     ) AS FLOAT) AS BIGINT))
                  END) AS MAX_LENGTH'

                  print(@sql)

Msg 512, Level 16, State 1, Line 101
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

我也尝试使用游标和“查询成功执行”,但即使没有关闭和释放游标,我也看不到结果。

DECLARE @SchemaName SYSNAME = 'dbo'
DECLARE @TableName SYSNAME 
DECLARE @ColumnName SYSNAME


DECLARE FLOAT_COLUMNS CURSOR FOR
SELECT t.name,c.name 
  FROM BRSDATA.sys.tables AS t
  INNER JOIN BRSDATA.sys.schemas AS s
  ON t.[schema_id] = s.[schema_id]
  inner join BRSDATA.sys.columns AS c
  on c.object_id = t.object_id
  WHERE s.name = 'dbo'
  and type_desc = 'USER_TABLE';

OPEN FLOAT_COLUMNS

FETCH NEXT FROM FLOAT_COLUMNS
INTO @TableName, @ColumnName

    WHILE @@FETCH_STATUS = 0
    BEGIN

       DECLARE @Columns NVARCHAR(MAX)
       SET @Columns = 
       STUFF(
          (SELECT
             ',' + QUOTENAME(name)
          FROM
             sys.columns
          WHERE
             object_id = OBJECT_ID(QUOTENAME(@TableName) + '.' + QUOTENAME(@ColumnName))
          FOR XML PATH(''))
          ,1,1,'')

        DECLARE @SQL AS NVARCHAR(MAX)
        SET @SQL = 'SELECT' + QUOTENAME(@TableName) + ',' + QUOTENAME(@ColumnName) +  ', MAX(CASE Charindex(''.'',' + @Columns + ')
                    WHEN 0 THEN 0
                    ELSE
   Len (Cast(Cast(Reverse(CONVERT(VARCHAR(50), ' + @Columns + ', 128)
                     ) AS FLOAT) AS BIGINT))
                  END) AS MAX_LENGTH'

        --use print to view and copy your dynamic sql string to see if you have formed it correctly
        PRINT @SQL
        --EXECUTE (@SQL)

        FETCH NEXT FROM FLOAT_COLUMNS
        INTO @TableName, @ColumnName
    END

CLOSE FLOAT_COLUMNS
DEALLOCATE FLOAT_COLUMNS

【问题讨论】:

  • 您真的在第二个中得到任何生成的 SQL 吗?目前 EXECUTE 被注释掉,所以它不会执行。当我在我的数据库上尝试你的 SQL 时,我没有打印任何 SQL。
  • 我发现您的变量 COLUMNS 似乎总是出现 NULL,因此 SQL 总是出现 NULL
  • @Cato - 我没有在动态 SQL 中生成任何 SQL。它给了我错误。当我单独运行“选择”时,我会得到数据库中的列列表。

标签: sql sql-server sql-server-2008-r2


【解决方案1】:

不确定这是否是您需要的,但我会这样做:

   DECLARE @cols NVARCHAR(MAX)
    ,@table NVARCHAR(MAX)
    ,@sql NVARCHAR(MAX)
    ,@X INT = 1


WHILE @X < (
    SELECT MAX(ROWID) FROM 
    (
        SELECT quotename(COLUMN_NAME) col
        ,ROW_NUMBER()over(ORDER BY COLUMN_NAME) ROWID
        FROM INFORMATION_SCHEMA.COLUMNS A
        inner join INFORMATION_SCHEMA.TABLES B
        on A.TABLE_NAME = B.TABLE_NAME
        where TABLE_TYPE = 'BASE TABLE'
        and DATA_TYPE = 'Float'
    ) AS X
  WHERE ROWID < 10
)
 BEGIN

SET @cols = 
(SELECT col FROM 
(
    SELECT quotename(COLUMN_NAME) col
    ,ROW_NUMBER()over(ORDER BY COLUMN_NAME) ROWID
    FROM INFORMATION_SCHEMA.COLUMNS A
    inner join INFORMATION_SCHEMA.TABLES B
    on A.TABLE_NAME = B.TABLE_NAME
    where TABLE_TYPE = 'BASE TABLE'
    and DATA_TYPE = 'Float'
) AS X
WHERE ROWID = @X 
)

SET @table = 
(SELECT tablename FROM 
(
    SELECT quotename(A.TABLE_NAME) tablename
    ,ROW_NUMBER()over(ORDER BY COLUMN_NAME) ROWID
    FROM INFORMATION_SCHEMA.COLUMNS A
    inner join INFORMATION_SCHEMA.TABLES B
    on A.TABLE_NAME = B.TABLE_NAME
    where TABLE_TYPE = 'BASE TABLE'
    and DATA_TYPE = 'Float'
) AS X
WHERE ROWID = @X 
)


Set @sql =  'SELECT MAX(CASE Charindex(''.'',' + @cols + ')
                    WHEN 0 THEN 0
                    ELSE
        Len (Cast(Cast(Reverse(CONVERT(VARCHAR(50), ' + @cols + ', 128)
                     ) AS FLOAT) AS BIGINT))
                  END) AS MAX_LENGTH
        ,MAX(CASE Charindex(''.'',' + @table + ')
                    WHEN 0 THEN 0
                    ELSE
        Len (Cast(Cast(Reverse(CONVERT(VARCHAR(50), ' + @table + ', 128)
                     ) AS FLOAT) AS BIGINT))
                  END) AS MAX_LENGTH'

PRINT(@sql)
SET @X = @X +1
END

【讨论】:

  • 谢谢。如何在@sql 中包含表名?它生成 sql 查询,但我缺少表名
  • 我为表格添加了另一个变量,但我不确定这是否是您需要的。
  • 谢谢。我刚刚将 at sql 更改为此.....'SELECT MAX(CASE Charindex(''.'',' + (at cols + ') WHEN 0 THEN 0 ELSE Len (Cast(Cast(Reverse(CONVERT(VARCHAR (50), ' + at cols + ', 128) ) AS FLOAT) AS BIGINT)) END) AS MAX_LENGTH From' + at table 我有我需要的东西
【解决方案2】:

我相信这个脚本可以帮助你:

DECLARE @Query TABLE (SchemaName    VARCHAR(100)
                    ,TableName  VARCHAR(100)
                    ,ColumnName VARCHAR(1000)
                    )
INSERT INTO @Query
SELECT A.TABLE_SCHEMA,A.TABLE_NAME,' MAX(CASE Charindex(''.'',' + QUOTENAME(COLUMN_NAME) + ') 
                                        WHEN 0 THEN 0 
                                        ELSE Len (Cast(Cast(Reverse(CONVERT(VARCHAR(50), ' + QUOTENAME(COLUMN_NAME) + ', 128) ) AS FLOAT) AS BIGINT)) 
                                        END) AS ['+COLUMN_NAME+'_MAX_LENGTH]'
FROM INFORMATION_SCHEMA.COLUMNS A
INNER JOIN INFORMATION_SCHEMA.TABLES B
ON A.TABLE_NAME = B.TABLE_NAME
WHERE TABLE_TYPE = 'BASE TABLE'
AND DATA_TYPE = 'FLOAT'

SELECT 'SELECT '+
        STUFF((
            SELECT ',' + ColumnName
            FROM @Query Q2
            WHERE Q1.SchemaName=q2.SchemaName AND  Q1.TableName=q2.TableName
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)')
            , 1, 2, '')
            +' FROM '+Q1.SchemaName+'.'+Q1.TableName
FROM 
(SELECT DISTINCT SchemaName,TableName FROM @Query) Q1

【讨论】:

  • 谢谢,脚本运行并生成动态 SQL 但它有这些额外的字符 ' ' 像这样 'SELECT MAX(CASE Charindex('.',[URBAN]) WHEN 0 然后 0 .....'
  • @user176047 。这是因为 STUFF 查询。我现在已经更新了。
  • 谢谢。我还在“MAX”之前添加了一个空格,因为 M 在第一个“Max”语句中被截断并导致“Ax”。
  • @user176047 。你说的对。我现在已经更正了脚本。
【解决方案3】:
use BRSDATA;

begin try drop table #temp end try begin catch end catch ;

DECLARE @TableName nvarchar(250); 
DECLARE @ColumnName nvarchar(250); 

declare @x int;

DECLARE @FLOATV as float = 3.141592653;--searching for this in all float vals in all tables

SELECT t.name,c.name colname 
    into #temp
  FROM sys.tables AS t
  INNER JOIN sys.schemas AS s
  ON t.[schema_id] = s.[schema_id]
  inner join sys.columns AS c
  on c.object_id = t.object_id
  WHERE s.name = 'dbo'
  and type_desc = 'USER_TABLE'
  and exists(select * from  sys.types where name = 'float' and system_type_id = c.system_type_id);

  SET Nocount on;

  DECLARE FLOAT_TAB CURSOR FOR
    SELECT DISTINCT [name] from #temp;
        OPEN FLOAT_TAB;
        FETCH NEXT FROM FLOAT_TAB
        INTO @TableName;

        WHILE @@FETCH_STATUS = 0
        BEGIN
            DECLARE @SQL nvarchar(max) = '';
            DECLARE @COND nvarchar(max) = '';
            SET  @SQL = 'SELECT ';

             DECLARE COL_TAB CURSOR FOR
                SELECT colname from #temp where name = @TableName;
                    OPEN COL_TAB;
                    FETCH NEXT FROM COL_TAB
                        INTO @ColumnName;

                WHILE @@FETCH_STATUS = 0
                BEGIN

                    SET @SQL = @SQL + ' ' + @ColumnName + ',';
                    SET @COND = @COND + @ColumnName + ' = ' + cast(@floatv as nvarchar(60)) + ' OR ' ;
                    FETCH NEXT FROM col_tab INTO @ColumnName

                END

                SET @SQL = LEFT(@SQL, len(@sql) - 1) + ' FROM ' + @TableName +  ' WHERE ' + LEFT(@COND, LEN(@COND) - 3);
                print @sql;
                EXECUTE ( @SQL);
                close col_tab;
                deallocate col_tab;
                --waitfor  delay '00:05';
            FETCH NEXT FROM FLOAT_TAB into @tablename;
        END
        close float_tab
        deallocate float_tab;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-26
    • 1970-01-01
    • 2021-12-16
    • 2021-11-17
    • 2020-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多