'insert into'with array

时间:2011-01-18 03:07:13

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

我想知道是否有办法在值列表中使用'insert into'。我正在尝试这样做:

insert into tblMyTable (Col1, Col2, Col3)
     values('value1', value2, 'value3')

所以,我想说的是value2将是一个字符串数组。我将把它放在C#中,但SQL语句是我真正需要的。我知道我可以使用foreach并循环遍历我的数组,但我认为可能有更好的方式类似于SELECT语句:SQL SELECT * FROM XXX WHERE columnName in Array。似乎单个查询比一次查询效率更高。

我正在使用SQL Server 2008 R2。谢谢fellas!

3 个答案:

答案 0 :(得分:4)

您可以使用此类型的插入语句

insert into tblMyTable (Col1, Col2, Col3)
select 'value1', value, 'value3'
from dbo.values2table('abc,def,ghi,jkl',',',-1) V

'值''value3'和' abc,def,ghi,jkl'是您需要的3个varchar参数在C#SQLCommand中设置。

这是所需的支持功能。

CREATE function dbo.values2table
(
@values varchar(max),
@separator varchar(3),
@limit int -- set to -1 for no limit
) returns @res table (id int identity, [value] varchar(max))
as
begin
declare @value varchar(50)
declare @commapos int, @lastpos int
set @commapos = 0
select @lastpos = @commapos, @commapos = charindex(@separator, @values, @lastpos+1)
while @commapos > @lastpos and @limit <> 0
begin
    select @value = substring(@values, @lastpos+1, @commapos-@lastpos-1)
    if @value <> '' begin
        insert into @res select ltrim(rtrim(@value))
        set @limit = @limit-1
    end
    select @lastpos = @commapos, @commapos = charindex(@separator, @values, @lastpos+1)
end
select @value = substring(@values, @lastpos+1, len(@values))
if @value <> '' insert into @res select ltrim(rtrim(@value))
return
end
GO

使用的参数是:

  1. ','= delimiter
  2. -1 =数组中的所有值,或仅为前N个项目的N
  3. 解决方案在上面,

    以下的替代方案

    或者,如果你喜欢,纯粹的CTE方法没有任何拆分功能支持(观看评论&lt;&lt;&lt;&lt;)

    ;WITH T(value,delim) AS (
         select 'abc,def,ghi', ','   --- <<< plug in the value array and delimiter here
    ),  CTE(ItemData, Seq, I, J) AS (
        SELECT
            convert(varchar(max),null),
            0,
            CharIndex(delim, value)+1,
            1--case left(value,1) when ' ' then 2 else 1 end
        FROM T
        UNION ALL
        SELECT
            convert(varchar(max), subString(value, J, I-J-1)),
            Seq+1,
            CharIndex(delim, value, I)+1, I
        FROM CTE, T
        WHERE I > 1 AND J > 0
        UNION ALL
        SELECT
            SubString(value, J, 2000),
            Seq+1,
            CharIndex(delim, value, I)+1, 0
        FROM CTE, T
        WHERE I = 1 AND J > 1
    )
    
    --- <<< the final insert statement
    insert into tblMyTable (Col1, Col2, Col3)
    SELECT 'value1', ItemData, 'value3'
    FROM CTE
    WHERE Seq>0
    

    XML方法

    -- take an XML param
    declare @xml xml
    set @xml = '<root><item>abc</item><item>def</item><item>ghi</item></root>'
    
    insert into tblMyTable (Col1, Col2, Col3)
    SELECT 'value1', n.c.value('.','varchar(max)'), 'value3'
    FROM @xml.nodes('/root/item') n(c)
    
    -- heck, start with xml string
    declare @xmlstr nvarchar(max)
    set @xmlstr = '<root><item>abc</item><item>def</item><item>ghi</item></root>'
    
    insert tblMyTable (Col1, Col2, Col3)
    SELECT 'value1', n.c.value('.','varchar(max)'), 'value3'
    FROM (select convert(xml,@xmlstr) x) y
    cross apply y.x.nodes('/root/item') n(c)
    

    在C#代码中,您只能使用以“insert tblMyTable ...”开头的4行,并参数化@xmlstr变量。

答案 1 :(得分:3)

由于您使用的是SQL 2008和C#,最好的选择可能是使用table valued parameter,然后加入它。

这比传递逗号分隔的字符串更好,因为您不必担心值中的引号和逗号。

<强>更新 另一种选择是使用xml data type

Pre-SQL 2005的另一个选择是传递XML字符串并使用OPENXML。如果您使用XMLWriter创建字符串,则需要确保您的xml有效

答案 2 :(得分:1)

-- This table is meant to represent the real table you
-- are using, so when you write this replace this one.
DECLARE @tblMyTable TABLE
(
 Value1 VARCHAR(200)
 , Value2 VARCHAR(200)
 , Value3 VARCHAR(200)
);

-- You didn't say how you were going to get the string
-- array, so I can't do anything cool with that. I'm
-- just going to say we've made a table variable to
-- put those values in. A user-defined table type
-- might be in order here.
DECLARE @StringArray TABLE
(
 Value VARCHAR(200)
);

INSERT INTO @StringArray
VALUES ('Jeremy'), ('snickered'), ('LittleBobbyTables'), ('xkcd Reference');

DECLARE @Value1 VARCHAR(200) = 'This guy --->';
DECLARE @Value3 VARCHAR(200) = ' <--- Rocks!';

-- I want to cross apply the two constant values, so
-- they go into a CTE, which makes them as good as
-- in a table.
WITH VariablesIntoTable AS
(
 SELECT
  @Value1 AS Value1
  , @Value3 AS Value3
)
-- Cross applying the array couples every row in the
-- array (which is in a table variable) with the two
-- variable values.
, WithStringArray AS
(
 SELECT
  VariablesIntoTable.Value1
  , StringArray.Value AS Value2
  , VariablesIntoTable.Value3
 FROM VariablesIntoTable
 CROSS APPLY @StringArray StringArray
)
INSERT INTO @tblMyTable
-- The output clause allows you to see what you just
-- inserted without a separate select.
OUTPUT inserted.Value1, inserted.Value2, inserted.Value3
SELECT
 WithStringArray.Value1
 , WithStringArray.Value2
 , WithStringArray.Value3
FROM WithStringArray