8

这可能是一个有限但有价值的场景。我有一个带有数百万条记录的表的 SQL Server 2008 数据库。一些记录似乎存在间歇性问题。我正在尝试重现问题。为了做到这一点,我终于得到了违规记录的 ID。我想在我的 PROD 数据库中生成与这条记录相关联的 INSERT 语句。然后我可以轻松地将它迁移到我的 TESTING 数据库中,以便重现和解决问题。

基本上,我需要从我知道记录的主键值的单个表中为单个记录生成单个 INSERT 语句。

有人对我如何做到这一点有任何想法吗?本质上,我想根据条件生成插入语句。

谢谢!

4

3 回答 3

5

SELECT首先尝试使用语句重新创建要插入的内容。

之后,您可以像这样插入表中INSERT INTO

INSERT INTO tablename
SELECT ....

如果它们在不同的服务器上,您可以像这样使用 INSERT:

INSERT INTO tablename VALUES (...)

使用SELECT其他服务器中给出的值填充插入中的值。

于 2012-05-17T13:13:12.970 回答
5

在您的具体情况下,我认为您可以这样做:

CREATE PROCEDURE dbo.GenerateSingleInsert
    @table     NVARCHAR(511), -- expects schema.table notation
    @pk_column SYSNAME,       -- column that is primary key
    @pk_value  INT            -- change data type accordingly
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @cols   NVARCHAR(MAX), @vals   NVARCHAR(MAX),
            @valOut NVARCHAR(MAX), @valSQL NVARCHAR(MAX);

    SELECT @cols = N'', @vals = N'';

    SELECT @cols = @cols + ',' + QUOTENAME(name),
           @vals = @vals + ' + ' + REPLICATE(CHAR(39),3) + ',' 
            + REPLICATE(CHAR(39),3) + ' + ' + REPLICATE(CHAR(39),2) + '+'
            + 'RTRIM(' + CASE WHEN system_type_id IN (40,41,42,43,58,61) THEN
             'CONVERT(CHAR(8), '  + QUOTENAME(name) + ', 112) + '' '' 
            + CONVERT(CHAR(14), ' + QUOTENAME(name) + ', 14)'
            ELSE 'REPLACE(' + QUOTENAME(name) + ','''''''','''''''''''')' END + ') 
            + ' + REPLICATE(CHAR(39),2)
      FROM sys.columns WHERE [object_id] = OBJECT_ID(@table)
      AND system_type_id <> 189 -- can't insert rowversion
      AND is_computed = 0;      -- can't insert computed columns

    SELECT @cols = STUFF(@cols, 1, 1, ''),
           @vals = REPLICATE(CHAR(39), 4) + ' + ' + STUFF(@vals, 1, 13, '') 
            + REPLICATE(CHAR(39), 2);

    SELECT @valSQL = N'SELECT @valOut = ' + @vals + ' FROM ' + @table + ' WHERE '
        + QUOTENAME(@pk_column) + ' = ''' + RTRIM(@pk_value) + ''';';

    EXEC sp_executesql @valSQL, N'@valOut NVARCHAR(MAX) OUTPUT', @valOut OUTPUT;

    SELECT SQL = 'INSERT ' + @table + '(' + @cols + ') SELECT ' + @valOut;
END
GO

所以让我们尝试一下:

CREATE TABLE dbo.splunge
(
    ID INT, dt DATETIME, rv ROWVERSION, t NVARCHAR(MAX)
);

INSERT dbo.splunge(ID, dt, t)
          SELECT 1, GETDATE(), 'foo'
    UNION ALL SELECT 2, GETDATE(), 'bar'
    UNION ALL SELECT 3, GETDATE(), 'O''Brien';

EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 1;

SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '1','20120517 10:07:07:330','foo'

EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 2;

SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '2','20120517 10:07:07:330','bar'

EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 3;

SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '3','20120517 10:07:07:330','O''Brien'

如果有 IDENTITY 列,您可能需要为 TEST 表设置 SET IDENTITY_INSERT ON,并验证没有冲突。我应该提到大约 500 个警告,我还没有测试所有数据类型等。

然而,在更一般的情况下它的作用远不止于此。Vyas K 有一个非常健壮的存储过程,应该可以证明它可以变得多么复杂:

http://vyaskn.tripod.com/code/generate_inserts_2005.txt

使用Red-Gate 的 SQL 数据比较之类的工具来选择特定行并为您生成插入可能会好得多。正如我在博客中提到的那样,为工具付费不仅仅是为了钱,还在于其他人已经为您完成的故障排除和错误修复的时间。

于 2012-05-17T14:19:33.170 回答
2

Aaron,我喜欢你的代码,它为我解决了一个问题。我在使用 null 和 text 类型时遇到了一些问题(就像你说的那样),所以我做了一些更改来解决这些问题。

ALTER PROCEDURE dbo.GenerateSingleInsert
@table     NVARCHAR(511), -- expects schema.table notation
@pk_column SYSNAME,       -- column that is primary key
@pk_value  INT            -- change data type accordingly
AS
BEGIN
SET NOCOUNT ON;

DECLARE @cols   NVARCHAR(MAX), @vals   NVARCHAR(MAX),
        @valOut NVARCHAR(MAX), @valSQL NVARCHAR(MAX);

SELECT @cols = N'', @vals = N'';

SELECT @cols = @cols + ',' + QUOTENAME(name),
       @vals = @vals + ' + '','' + ' + 'ISNULL('+REPLICATE(CHAR(39),4)+'+RTRIM(' + 
                                        CASE WHEN system_type_id IN (40,41,42,43,58,61) -- datetime types
                                        THEN
                                            'CONVERT(CHAR(8), '  + QUOTENAME(name) + ', 112) + '' ''+ CONVERT(CHAR(14), ' + QUOTENAME(name) + ', 14)'
                                        WHEN system_type_id IN (35) -- text type NOTE: can overflow
                                        THEN
                                            'REPLACE(CAST(' + QUOTENAME(name) + 'as nvarchar(MAX)),'+REPLICATE(CHAR(39),4)+','+REPLICATE(CHAR(39),6)+')' 
                                        ELSE 
                                            'REPLACE(' + QUOTENAME(name) + ','+REPLICATE(CHAR(39),4)+','+REPLICATE(CHAR(39),6)+')' 
                                        END 
                                + ')+' + REPLICATE(CHAR(39),4) + ',''null'') + '

  FROM sys.columns WHERE [object_id] = OBJECT_ID(@table)
  AND system_type_id <> 189 -- can't insert rowversion
  AND is_computed = 0;      -- can't insert computed columns

SELECT @cols = STUFF(@cols, 1, 1, ''),
       @vals = REPLICATE(CHAR(39),2) + STUFF(@vals, 1, 6, '') + REPLICATE(CHAR(39),2) ;

SELECT @valSQL = N'SELECT @valOut = ' + @vals + ' FROM ' + @table + ' WHERE '
    + QUOTENAME(@pk_column) + ' = ''' + RTRIM(@pk_value) + ''';';

EXEC sp_executesql @valSQL, N'@valOut NVARCHAR(MAX) OUTPUT', @valOut OUTPUT;

SELECT SQL = 'INSERT ' + @table + '(' + @cols + ') SELECT ' + @valOut;
END
于 2013-10-16T22:58:03.717 回答