2011-01-18 4 views
8

Je me demande s'il existe un moyen d'utiliser 'insert into' dans une liste de valeurs. Je suis en train de le faire:'insert into' with array

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

Alors, ce que je veux dire est que valeur2 sera un tableau de chaînes. Je vais mettre cela en C# mais l'instruction SQL est tout ce dont j'ai vraiment besoin. Je sais que je pourrais juste utiliser une foreach et une boucle à travers mon tableau, mais j'ai pensé qu'il pourrait y avoir un meilleur moyen de ressembler à l'instruction SELECT ici: SQL SELECT * FROM XXX WHERE columnName in Array. Il semble qu'une seule requête serait beaucoup plus efficace qu'une seule à la fois. J'utilise SQL Server 2008 R2. Merci les gars!

+1

Vous pouvez spécifier plusieurs lignes 'values'. Je voudrais simplement générer le SQL par programmation dans ce cas (vous pouvez même utiliser des espaces réservés avec le truc SqlCommand! Aucune injection de chaîne moche requise).Si vous voulez vraiment passer un "tableau", considérez le type XML et un sproc à faire - enfin, à peu près ce que ferait le code C#. Vous pouvez décomposer le type XML en un type de table, mais au détriment d'un sproc/T-SQL, vous ne savez pas si c'est une approche que vous * voulez * prendre. –

+0

Wow, je ne savais pas que vous pouviez faire plusieurs lignes 'values' jusqu'à maintenant. Placeholders dans SqlCommand()? Pouvez-vous me donner un petit exemple de ce dont vous parlez? Les seuls espaces réservés dont j'ai entendu parler sont pour ASP.NET mais mon application est un Windows Form ... – snickered

+0

@pst - Vous avez répondu à ma question mais je ne peux pas vous donner de crédit puisque c'est dans les commentaires. Repost dans les réponses si ça vous intéresse ... – snickered

Répondre

4

Vous pouvez utiliser ce type d'instruction d'insertion

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

La 'valeur' ​​, 'value3' et 'abc, def, ghi, JKL' sont les 3 paramètres varchar dont vous avez besoin pour définir dans C# SQLCommand.

Ceci est la fonction de support requise.

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 

Les paramètres utilisés sont les suivants:

  1. '' = délimiteur
  2. -1 = toutes les valeurs de la matrice, ou N pour seulement N premiers points
solution est

ci-dessus, alternatives ci-dessous

Ou, si vous préférez, une approche purement CTE non soutenue par une fonction de split (watch comme nts avec < < <)

;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 

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

Dans le code C#, vous n'utiliser 4 lignes commençant par "insérer tblMyTable ..." et paramétrez la variable @xmlstr.

+1

Pourquoi? Si cela ne doit pas arriver trop souvent, c'est une manière parfaitement cromante de le faire. – anon

+0

@pst - Je suis dans l'obscurité; c'est à propos de quoi?? – RichardTheKiwi

+0

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

3

Puisque vous utilisez SQL 2008 et C#, votre meilleur pari est probablement d'utiliser un table valued parameter puis de s'y joindre. Cela vaut mieux que de passer une chaîne délimitée par des virgules, car vous n'avez pas à vous soucier des guillemets et des virgules dans vos valeurs.

mise à jour Une autre option consiste à utiliser le xml data type.

Pré-SQL 2005 une autre option consiste à passer une chaîne XML et à utiliser OPENXML. Si vous utilisez un XMLWriter pour créer votre chaîne, il s'assurera que votre xml est valide

+0

OPENXML .. vraiment? Pas le type de données XML et les requêtes XPath? – RichardTheKiwi

+0

@cyperkiwi ne sais pas ce que je pensais. Mise à jour ma réponse –

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