是否可以通过对所有表进行相同的修改来更新数据库中的一堆不同的表?

时间:2019-04-05 13:37:59

标签: c# sql-server

我想复制我在SQL Server中的所有表,所有表名都应该在开头添加“ temp”。并且所有这些都将添加一个额外的列(全部相同)。我不需要完整的代码,而只是一般性的想法。

2 个答案:

答案 0 :(得分:1)

尝试此代码:

获取所有表名形式的信息模式并运行动态sql创建表

DECLARE @script varchar(max)

DECLARE db_cursor CURSOR FOR 
SELECT script = 'Select * Into  [temp'+ TABLE_NAME +'] From ' + QUOTENAME(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES


OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO @script  

WHILE @@FETCH_STATUS = 0  
BEGIN  

      EXEC(@script)
      --PRINT @script

      FETCH NEXT FROM db_cursor INTO @script
END 

CLOSE db_cursor  
DEALLOCATE db_cursor 

答案 1 :(得分:1)

一种直接的方法:

  1. 您需要从数据库中获取表名(可能使用INFORMATION_SCHEMA.TABLES)。
  2. 对于步骤1中的每个表,您需要生成一个相应的SELECT ... INTO语句。
  3. 您需要执行第2步中生成的每个SQL语句。

您已经有了使用光标的解决方案。这是没有光标的一个:

DECLARE @script VARCHAR(MAX) = '';
SELECT @script = @script + 'SELECT * INTO [temp'+ TABLE_NAME +'] FROM [' + TABLE_NAME + '];' + CHAR(13) + CHAR(10) FROM INFORMATION_SCHEMA.TABLES
EXEC (@script);

备注:CHAR(13)+ CHAR(10)不是必需的;如果您想首先检查脚本(使用PRINT而不是EXEC),则只是为了提高可读性而添加。

编辑:

注释中的一个附加问题可以在结果表中添加校验和值,如下所示:

DECLARE @script VARCHAR(MAX) = '';
SELECT @script = @script + 'SELECT CHECKSUM(*) AS [__checksum], * INTO [temp'+ TABLE_NAME +'] FROM [' + TABLE_NAME + '];' + CHAR(13) + CHAR(10) FROM INFORMATION_SCHEMA.TABLES
EXEC (@script);

使用HASHBYTES代替CHECKSUM可能更好,但是它仅接受两个参数:哈希算法和要哈希的单个值。因此,在这种情况下,您可能需要通过手动连接表的所有字段来传递字符串值,而在像我这样的动态查询中添加它可能有些麻烦。这可能会导致事情复杂,而不仅仅是三行...

嗯,实际上是这样的:

DECLARE @script NVARCHAR(MAX) = N'';

WITH
    [Columns] AS
    (
        SELECT
            TABLE_NAME AS [TableName],
            COLUMN_NAME AS [ColumnName],
            ROW_NUMBER() OVER (PARTITION BY TABLE_NAME ORDER BY ORDINAL_POSITION) AS [ColSeq]
        FROM
            INFORMATION_SCHEMA.COLUMNS
    ),
    [Tables] AS
    (
        SELECT
            [TableName],
            CAST(N'[' + [ColumnName] + N']' AS NVARCHAR(MAX)) AS [ColumnList],
            [ColSeq]
        FROM
            [Columns] AS C
        WHERE
            [ColSeq] = (SELECT MAX([ColSeq])
                        FROM [Columns]
                        WHERE [TableName] = C.[TableName]) 

    UNION ALL
        SELECT T.[TableName], N'[' + C.[ColumnName] + N'], ' + T.[ColumnList], C.[ColSeq]
        FROM
            [Tables] AS T
            INNER JOIN [Columns] AS C ON C.[TableName] = T.[TableName] AND C.[ColSeq] = T.[ColSeq] - 1
    )
SELECT @script = @script + N'SELECT HASHBYTES(''md5'', CONCAT(N'''', ' + [ColumnList] + N')) AS [__checksum], * INTO [temp' + [TableName] + N'] FROM [' + [TableName] + N'];' + NCHAR(13) + NCHAR(10)
FROM [Tables]
WHERE [ColSeq] = 1;

EXEC (@script);

备注:

  • 在递归CTE [Tables](用于以逗号分隔的字符串值连接每个表的列名)中,我从最后一列开始,并向后移动以缓解主查询中的过滤条件。
  • 我在结果N''的{​​{1}}调用中添加了一个附加的第一个参数CONCAT,因为@script函数需要至少2个参数,这很麻烦在这种情况下,只处理一列的表。

在这种情况下,尽管性能稍差,但使用游标可能更清晰,更容易,如@HasanMahmood在其答案中建议的那样...