2011-01-18 18 views
8

Mi chiedo se ci sia un modo per usare 'insert into' su un elenco di valori. Sto cercando di fare questo:'insert into' con array

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

Quindi, quello che sto cercando di dire è che valore2 sarà un array di stringhe. Inserirò questo in C# ma l'istruzione SQL è tutto ciò di cui ho davvero bisogno. So che potrei semplicemente usare un foreach e passare attraverso il mio array, ma ho pensato che potrebbe esserci un modo migliore una sorta di come l'istruzione SELECT qui: SQL SELECT * FROM XXX WHERE columnName in Array. Sembra che una singola query sia molto più efficiente di una alla volta.

Utilizzo SQL Server 2008 R2. Grazie ragazzi!

+1

È possibile specificare più righe "valori". In questo caso, avrei generato lo SQL in modo programmatico (è possibile utilizzare anche segnaposti con le risorse di SqlCommand! Non è richiesta alcuna iniezione brutto).Se vuoi veramente passare un "array", considera il tipo XML e una sproc da fare - beh, praticamente solo quello che farebbe il codice C#. È possibile scomporre il tipo XML in un tipo di tabella, ma a spese di uno sproc/T-SQL, non è sicuro se questo sia un approccio che * davvero * vuoi intraprendere. –

+0

Wow, non sapevo che potessi fare più linee "valori" fino ad ora. Segnaposto in SqlCommand()? Puoi darmi un piccolo esempio di cosa stai parlando? L'unico segnaposto di cui ho sentito parlare è ASP.NET ma la mia app è Windows Form ... – snickered

+0

@pst - Hai risposto alla mia domanda ma non posso darti credito poiché è nei commenti. Riprovare nelle risposte se ti interessa ... – snickered

risposta

4

È possibile utilizzare questo tipo di istruzione INSERT

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

Il 'valore', 'valore3' e 'abc, def, ghi, jkl' sono i 3 parametri varchar è necessario per impostare in C# SQLCommand.

Questa è la funzione di supporto richiesta.

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

I parametri utilizzati sono:

  1. '' = delimitatore
  2. -1 = tutti i valori nella matrice, o N per soli primi elementi N

soluzione è sopra, alternative sotto

Oppure, se si desidera, un approccio puramente CTE non supportato da alcuna funzione di divisione (guarda nti 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 

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

Nel codice C#, si può usare solo 4 linee che iniziano con "inserire tblMyTable ..." e parametrizzare la variabile @xmlstr.

+1

Perché? Se questo non deve accadere troppo spesso, è un modo perfettamente cromatico per farlo. – anon

+0

@ pst - Sono al buio; di cosa si tratta ?? – RichardTheKiwi

+0

Heh. +1 per essere [cromulent] (http://www.urbandictionary.com/define.php?term=Cromulent). –

3

Dal momento che si utilizza SQL 2008 e C# la soluzione migliore è probabilmente quella di utilizzare un table valued parameter e quindi partecipare a esso.

È meglio che passare una stringa delimitata da virgola perché non devi preoccuparti di virgolette e virgole nei valori.

aggiornamento Un'altra opzione è utilizzare xml data type.

Pre-SQL 2005 un'altra opzione è passare una stringa XML e utilizzare OPENXML. Se si utilizza un XMLWriter per creare la stringa, si avrà cura di assicurarsi che il proprio xml sia valido

+0

OPENXML .. davvero? Non il tipo di dati XML e le query XPath? – RichardTheKiwi

+0

@cyperkiwi non so cosa stavo pensando. Aggiornato la mia risposta –

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 
Problemi correlati