【问题标题】:'insert into' with array用数组“插入”
【发布时间】:2011-06-10 20:18:32
【问题描述】:

我想知道是否有一种方法可以在值列表中使用“插入”。我正在尝试这样做:

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。谢谢各位!

【问题讨论】:

  • 您可以指定多个“值”行。在这种情况下,我只会以编程方式生成 SQL(您甚至可以将占位符与 SqlCommand 一起使用!不需要丑陋的字符串注入)。如果您真的想传递一个“数组”,请考虑 XML 类型和一个存储过程——嗯,这几乎就是 C# 代码会做的事情。您可以将 XML 类型分解为表类型,但是以 sproc/T-SQL 为代价,不确定这是否是您真的想要采用的方法。
  • 哇,直到现在我才知道你可以做多个“值”行。 SqlCommand() 中的占位符?你能给我一个你在说什么的小例子吗?我听说的唯一占位符是 ASP.NET,但我的应用程序是 Windows 窗体...
  • @pst - 你回答了我的问题,但我不能给你信用,因为它在 cmets 中。如果您关心,请重新发布答案...
  • 再想一想,它只是一个用占位符生成所有值的 PITA(对于 不同 复杂的问题,我这样做很好)。仅在 same transaction 中运行所有插入应该具有大致相同的效果,除了带有触发器的病理情况等,但要简单得多 - 只需使用相同的 SqlCommand(ADO.NET 的一部分) ,可以被认为是“最基本的”访问)在一个循环中超过 N 次会简单得多。下面已经介绍了使用 XML 等:)
  • 好的,我将循环遍历或找出一种使用多个“值”的方法。无论哪种方式,下面的所有东西看起来都超出了我现在可以处理的范围。 XML 看起来很不错,所以我会把答案交给cyberwiki...

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


【解决方案1】:

你可以使用这种类型的插入语句

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

'value''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. ',' = 分隔符
  2. -1 = 数组中的所有值,或仅前 N 项的 N

解决方案在上面,替代方案在下面

或者,如果您喜欢,一种不受任何拆分函数支持的纯 CTE 方法(使用

;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 变量。

【讨论】:

  • 为什么?如果这种情况不必经常发生,那么这是一种完美的方式。
  • @pst - 我在黑暗中;这是关于什么的??
  • 嘿。 +1 cromulent
  • 是啊,我也要哭了。这些解决方案都在我的脑海中。我在想这将是一个更简单的查询,我可以轻松地将其放入 SqlCommand() 中。我错了!
  • @snickered - 好吧,我过头了。重新格式化第一部分以更清晰
【解决方案2】:

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

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

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

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

【讨论】:

  • OPENXML.. 真的吗?不是 XML 数据类型和 XPath 查询?
  • @cyperkiwi 不知道我在想什么。更新了我的答案
【解决方案3】:
-- 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

【讨论】:

    猜你喜欢
    • 2021-03-23
    • 2014-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    • 2021-01-12
    • 1970-01-01
    相关资源
    最近更新 更多