构建INSERT语句值的动态列表

时间:2013-12-17 12:50:51

标签: sql sql-server-2008

我正在编写一个存储过程来为管理员创建一组DELETE语句来对数据库运行

作为“回滚”解决方案的一部分,我希望,对于我要删除的每一行,还要单独创建相应的INSERT语句,以便运行脚本的人希望撤消,他们可以简单地对数据库运行insert语句

我的问题是,如果我有一个表有8列(Col1..Col8)的表,我如何在所有列的逗号分隔列表中提取值,以便我最终得到

INSERT INTO Table VALUES (Col1value, Col2value, ...Col8value)

5 个答案:

答案 0 :(得分:6)

请考虑以下命令:

SELECT 'SELECT ' +
    STUFF ((
        SELECT ', [' + name + ']'
        FROM syscolumns
        WHERE id = OBJECT_ID('Table') AND
            name <> 'me'
        FOR XML PATH('')), 1, 1, '') +
    ' FROM [Table]'

这将为特定表构建SELECT语句。要构建INSERT语句,它可能如下所示:

SELECT @sql = 'INSERT INTO [Table] (' +
    STUFF ((
        SELECT ', [' + name + ']'
        FROM syscolumns
        WHERE id = OBJECT_ID('Table') AND
            name <> 'me'
        FOR XML PATH('')), 1, 1, '') +
    ') VALUES (' +
    STUFF ((
        SELECT ', @' + name
        FROM syscolumns
        WHERE id = OBJECT_ID('Table') AND
            name <> 'me'
        FOR XML PATH('')), 1, 1, '') + ')'

当然有很多方法可以找到INSERT声明,根据自己的喜好来制作它。

答案 1 :(得分:2)

在等待其他专家的通用解决方案时,如果表结构已知并且稳定,这是一个适当的权宜版本。这个测试数据: -

create table #mytable (
    col1value varchar (50),
    col2value int,
    col3value decimal(10, 5),
    col4value date,
    col5value datetime
);

insert into #mytable values 
    (null,1,234.567,'2013-12-20','2013-01-07T17:30:24.567'),
    ('def',null,987.645,'2013-12-21','2013-01-01'),
    ('abc',17,null,'2013-12-20','2013-10-07T11:31:21.517'),
    ('jkl',2,3232.32,null,'2013-01-01 01:02:03.456'),
    ('mno',2,7.4006,'2012-07-04',null)

允许此代码: -

select 'insert into #myTable values (' +
    isnull('''' + col1value + '''','null') + ',' +
    isnull(convert(varchar(50),col2value),'null') + ',' + 
    isnull(convert(varchar(50),col3value),'null') + ',' +
    isnull('''' + convert(varchar(50),col4value) + '''','null') + ',' +
    isnull('''' + convert(varchar(50),col5value,121) + '''','null') + 
    ')'
from #mytable

制作: -

insert into #myTable values (null,1,234.56700,'2013-12-20','2013-01-07 17:30:24.567')
insert into #myTable values ('def',null,987.64500,'2013-12-21','2013-01-01 00:00:00.000')
insert into #myTable values ('abc',17,null,'2013-12-20','2013-10-07 11:31:21.517')
insert into #myTable values ('jkl',2,3232.32000,null,'2013-01-01 01:02:03.457')
insert into #myTable values ('mno',2,7.40060,'2012-07-04',null)

您可以通过在insert语句中包含列列表来防止结构更改(在某种程度上)。即使有列列表 - 如果有人在没有默认值的情况下向表中添加了一个不可为空的列 - 您的插入将失败(除非您在更改架构时按下它们)。

我总是会使用代码工厂来生成这种代码(即在信息模式上运行的SP - 使用列类型来构建代码以序列化每种类型的值)。

上面的示例仅处理您可能需要处理的一些类型 - 但您应该能够找出如何处理所有其他类型。

答案 2 :(得分:0)

您可以创建一个临时表,然后在您的过程中插入一行,将该行添加到您的temprory表中。 当此人想撤消时只需获取表格的最后一行(插入时添加一个带有时间或日期的额外列)并在主表中插入此行。

希望这有帮助。

答案 3 :(得分:0)

如果您使用第三方工具,则可以使用SSMS Tools Pack

它是版本2005,2008,2008 R2和2012的Microsoft SQL Server Management Studio(SSMS)加载项。

它可以做很多事情,包括:为表,视图或整个数据库生成插入语句(参见功能页面:Insert statement generator)。

我自己用它做你要问的同样的事情:为大量数据记录创建一个备份,这样我们就可以轻松地回滚我们的更改。

答案 4 :(得分:0)

这将起作用..传递表名,要应用条件的列名并传递条件。喜欢exec sp_get_columns 'tbl_name', 'column_name', '100'

CREATE or ALTER PROCEDURE SP_GET_COLUMNS
@TABLE_NAME varchar(256)
,@COND_COL varchar(256)
,@COND varchar(256)
AS
BEGIN            
SELECT IDENTITY(int, 1, 1) seq_no, COLUMN_NAME into #temp FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TABLE_NAME
Declare @Data AS Nvarchar(MAX) 
SELECT @Data = COALESCE(@Data + ','','',', '') + COLUMN_NAME FROM  #temp
DECLARE @query varchar(1000) = 'SELECT CONCAT(' + @Data + ') from ' + @TABLE_NAME + ' where ' + @COND_COL + ' = ''' + @COND + ''''
CREATE TABLE #temp2 (val VARCHAR(8000))
INSERT INTO #temp2 exec(@query)
SELECT REPLACE(REPLACE(CONCAT('INSERT INTO ',@TABLE_NAME,' VALUES(''', REPLACE(val,',',''',''') ,''')'),',''''',',NULL'),','''',',',NULL,') as Query FROM #temp2
drop Table #temp,#temp2
END