从所有表复制,插入所有表(sp_MSforeachtable替代)

时间:2012-11-02 10:56:16

标签: sql sql-server sp-msforeachtable

我决定分享我尝试将所有表中的数据复制到不同架构中的相同名称表的经验。我确信我的经验可以帮助其他人在不使用不受支持和坦率限制sp_MSforeachtable的情况下寻求大规模表操作。

目标:将数据库中所有表的数据复制到具有不同架构的同名表

关于 sp_MSforeachtable的一个简短说明。 大多数时候,当人们在SO中提出有关此存储过程的问题时,会有一些回复或其他说法,我们不应该使用不受支持的功能。这根本不是真的,我们不应该做的是根据不支持的功能进行实践和设计决策,主要是因为它们可能会消失。 但是在某个特定的时间点,如果存在一个不受支持的功能并完全按照我们需要做的那样,一次性风格,那么只要认为自己很幸运,并且无论如何都要使用它,只需要注意意外行为。使用此类功能时,最好坚持使用简单的操作,其输出可以快速,轻松地验证。

话虽如此,也因为sp_MSforeachtable存在一些实际限制,我提出了一种不同但不太复杂的方法来对数据库中的所有(或特定)表执行语句,而我正在使用我的问题就是一个例子。

1 个答案:

答案 0 :(得分:1)

我经常通过生成返回语句的查询来解决此问题,然后将这些语句复制粘贴到新的查询窗口并执行它们。我喜欢这种方法,因为我在执行它之前会看到我的语句,并且还可以使用解析器快速识别它们的问题。考虑到这一点,这是我的问题:

SELECT DISTINCT ''
    + ' INSERT INTO ' + 'dbo.' + QUOTENAME(name)
    + ' (' + dbo.COLUMN_NAMES('dbo', name) + ')'
    + ' SELECT ' + dbo.COLUMN_NAMES('dbo', name)
    + ' FROM ' + 'db_owner.' + QUOTENAME(name)
FROM sys.tables
-- add your own WHERE clauses to only execute against specific tables

就这么简单。这将返回一个INSERT INTO ... SELECT FROM ...语句列表,我只需将其复制到一个新的查询窗口即可。

如果您想知道为什么不使用SELECT *,那只是因为如果您的表有ID列,那么您需要显式命名列并在之前和之后添加SET_IDENTITY语句。

COLUMN_NAMES函数是一个非常不言自明的函数,它返回指定表的逗号分隔列名:

CREATE FUNCTION COLUMN_NAMES
(
    @tableschema VARCHAR(MAX),
    @tablename VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN

RETURN (
    REPLACE(
        (SELECT QUOTENAME(COLUMN_NAME) AS 'data()'
         FROM INFORMATION_SCHEMA.COLUMNS
         WHERE TABLE_SCHEMA=@tableschema AND TABLE_NAME=@tablename ORDER BY ORDINAL_POSITION FOR XML PATH('')),
         ' ',', '))

END
GO