2011-01-18 19 views
8

Me pregunto si hay una forma de usar 'insert into' en una lista de valores. Estoy tratando de hacer esto:'insert into' con array

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

Por lo tanto, lo que estoy tratando de decir es que valor2 será una matriz de cadenas. Voy a poner esto en C# pero la declaración de SQL es todo lo que necesito realmente. Sé que podría usar un foreach y recorrer mi array, pero pensé que podría haber una forma mejor, como la instrucción SELECT aquí: SQL SELECT * FROM XXX WHERE columnName in Array. Parece que una única consulta sería mucho más eficiente que una a la vez.

Estoy usando SQL Server 2008 R2. Gracias muchachos!

+1

Puede especificar múltiples líneas de 'valores'. Generaría el SQL programáticamente en este caso (¡incluso puede usar marcadores de posición con las funciones SqlCommand! No se requiere inyección fea).Si realmente quieres pasar una "matriz", considera el tipo de XML y un sproc que hacer, bueno, más o menos lo que haría el código C#. Puede descomponer el tipo de XML en un tipo de tabla, pero a expensas de un sproc/T-SQL, no está seguro de si ese es un enfoque que * realmente * desea tomar. –

+0

Guau, no sabía que podría hacer múltiples líneas de 'valores' hasta ahora. Marcadores de posición en SqlCommand()? ¿Puedes darme un pequeño ejemplo de lo que estás hablando? Los únicos marcadores de posición de los que he oído hablar son de ASP.NET pero mi aplicación es Windows Form ... – snickered

+0

@pst - Respondiste mi pregunta, pero no puedo darte crédito porque está en los comentarios. Repost en las respuestas si te importa ... – snickered

Respuesta

4

Puede utilizar este tipo de instrucción de inserción

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

El 'valor', 'valor3' y 'abc, def, ghi, jkl' son los 3 parámetros varchar que necesita para establecer en C# SQLCommand.

Esta es la función de soporte necesaria.

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, @[email protected]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 

Los parámetros utilizados son:

  1. '' = delimitador
  2. -1 = todos los valores en la matriz, o N por sólo primeros artículos N

solución es arriba, alternativas debajo de

O, si lo desea, un enfoque puramente CTE no respaldado por ninguna función dividida (ver comme NTS con < < <)

;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 

enfoque 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) 

En código C#, sólo se usarían 4 líneas que comienzan por "insertar tblMyTable ..." y parametrizar la variable @xmlstr.

+1

¿Por qué? Si esto no tiene que suceder muy a menudo, es una manera perfectamente cromática de hacer esto. – anon

+0

@pst - Estoy en la oscuridad; ¿¿De qué se trata esto?? – RichardTheKiwi

+0

Heh. +1 por ser [cromulento] (http://www.urbandictionary.com/define.php?term=Cromulent). –

3

Dado que está utilizando SQL 2008 y C# su mejor opción es probablemente utilizar un ay luego unirse a él.

Esto es mejor que pasar una cadena delimitada por comas porque no tiene que preocuparse por las comillas y las comas en sus valores.

actualización Otra opción es utilizar el xml data type.

Pre-SQL 2005 Otra opción es pasar una cadena XML y usar OPENXML. Si utiliza un XMLWriter para crear su cadena, se encargará de asegurarse de que su xml sea válido

+0

OPENXML .. ¿en serio? ¿No es el tipo de datos XML y las consultas XPath? – RichardTheKiwi

+0

@cyperkiwi no sé lo que estaba pensando. Actualizado mi respuesta –

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 
Cuestiones relacionadas