2013-03-23 8 views
10

Ich habe eine Liste von IDs durch Komma getrennt wie:Wie konvertiere ich NVARCHAR Kommata in Tabellensätze in SQL Server 2005 konvertieren?

1,17,25,44,46,67,88 

möchte ich sie in eine Tabelle Datensätze konvertieren (in eine temporäre Tabelle) wie

#tempTable 

number_ 
-------- 
1 
17 
25 
44 
46 
67 
88 

Es ist möglich, mit einer Funktion, ein Tabellenwert?

Warum möchte ich das? Ich mag für INNER JOIN Klausel (in Stored Procedure) mit einer anderen Tabelle (n) wie so verwenden:

SELECT a,b,c FROM T1 
INNER JOIN functionNameWhichReturnsTable 
ON functionNameWhichReturnsTable.number_ = T1.a 

ich IN verwenden kann nicht, weil ich gespeicherte Prozedur verwenden, die einen Parameter vom Typ NVARCHAR akzeptiert. Dieser Parameter liefert die Liste der IDs.

Danke

+0

mögliches Duplikat von [Eine kommagetrennte Zeichenfolge in einzelne Zeilen umwandeln] (http://stackoverflow.com/que stions/5493510/Durch Komma getrennte Zeichenketten in einzelne Zeilen) –

+0

mögliches Duplikat von [Split string in SQL] (http://stackoverflow.com/questions/2647/split-string-in-sql) –

Antwort

18

Mögliche Duplikat separate comma separated values and store in table in sql server.

Bitte versuchen, einen präzise eine von Comma-Delimited Value to Table:

CREATE FUNCTION [dbo].[ufn_CSVToTable] (@StringInput VARCHAR(8000), @Delimiter nvarchar(1)) 
RETURNS @OutputTable TABLE ([String] VARCHAR(10)) 
AS 
BEGIN 

    DECLARE @String VARCHAR(10) 

    WHILE LEN(@StringInput) > 0 
    BEGIN 
     SET @String  = LEFT(@StringInput, 
           ISNULL(NULLIF(CHARINDEX(@Delimiter, @StringInput) - 1, -1), 
           LEN(@StringInput))) 
     SET @StringInput = SUBSTRING(@StringInput, 
            ISNULL(NULLIF(CHARINDEX(@Delimiter, @StringInput), 0), 
            LEN(@StringInput)) + 1, LEN(@StringInput)) 

     INSERT INTO @OutputTable ([String]) 
     VALUES (@String) 
    END 

    RETURN 
END 
GO 

überprüfen Sie die Anforderung in anderer Art und Weise unter Verwendung von XML:

DECLARE @param NVARCHAR(MAX) 
SET @param = '1:0,2:1,3:1,4:0' 

SELECT 
    Split.a.value('.', 'VARCHAR(100)') AS CVS 
FROM 
(
    SELECT CAST ('<M>' + REPLACE(@param, ',', '</M><M>') + '</M>' AS XML) AS CVS 
) AS A CROSS APPLY CVS.nodes ('/M') AS Split(a) 
+0

Die XML-Aufteilung ist mehr als 3 mal langsamer als die Schleife! –

+0

XML-Split ist schneller als Schleife eins, wenn Sie Tausende von Werten in einer durch Komma getrennten Zeichenfolge haben, dh in @param – Gurunadh

2

Die Methode, die ich keine Funktion oder XML-Tricks muß gefunden.

Im Grunde transformieren Sie die Zeichenfolge in eine einzige INSERT-Anweisung für die temporäre Tabelle.
Welches kann dann für die weitere Verarbeitung verwendet werden.

IF OBJECT_ID('tempdb..#tempTable') IS NOT NULL DROP TABLE #tempTable; 
CREATE TABLE #tempTable (number int); 

DECLARE @TEXT varchar(max) = '1,17,25,44,46,67,88'; 

DECLARE @InsertStatement varchar(max) = 'insert into #tempTable values ('+REPLACE(@TEXT,',','),(')+');'; 
EXEC (@InsertStatement); 

SELECT * FROM #tempTable; 

Diese Methode ist für bis zu 1000 Werte verwendbar.
Da 1000 das maximale Limit eines Zeilenwertausdrucks ist.
Oder bis das Limit des varchar für @InsertStatement erreicht ist.

Auch, wie Stuart Ainsworth wies darauf hin.
Da diese Methode EXEC verwendet, achten Sie auf Code-Injection und verwenden Sie sie nicht für Strings, die auf nicht verifizierten Benutzereingaben basieren.

+0

Versuchen Sie diese Zeile: DECLARE @TEXT varchar (max) = '1,17,25,44,46 , 67,88); DELETE FROM #tempTable WHERE (1 = 1 '; SQL-Injektion ist mit dieser Methode möglich, aber nicht wahrscheinlich. –

+0

Es tut mir leid; Ich denke, Sie missverstanden. Ich legte eine DELETE-Anweisung in einen Text string, die von Ihrer exec-Anweisung ausgeführt werden. THat ist eine klassische Form der SQL-Injektion, mit genügend Privilegien könnte jemand alle möglichen Unfug tun (wie eine Datenbank löschen, Benutzer erstellen) ... –

+0

Wieder ist es nicht wahrscheinlich, aber dies ist ein Entwurfsmuster, das zu vermeiden ist –

0

die Antworten abschließen, können Sie auch die CSV-Zeichenfolge verwenden, um mehrere Werte in mehreren Spalten zu speichern:

--input sql text 
declare @text_IN varchar(max) ='text1, text1.2, text1.3, 1, 2010-01-01\r\n text2, text2.2, text2.3, 2, 2016-01-01' 

Split die CSV-Datei in Reihen:

declare @temptable table (csvRow varchar(max))  
declare @DelimiterInit varchar(4) = '\r\n' 
declare @Delimiter varchar(1) = '|' 
declare @idx int  
declare @slice varchar(max)  

set @text_IN = REPLACE(@text_IN,@DelimiterInit,@Delimiter) 


select @idx = 1  
    if len(@text_IN)<1 or @text_IN is null return  

while @idx!= 0  
begin  
    set @idx = charindex(@Delimiter,@text_IN)  
    if @idx!=0  
     set @slice = left(@text_IN,@idx - 1)  
    else  
     set @slice = @text_IN 

    if(len(@slice)>0) 
     insert into @temptable(csvRow) values(@slice)  

    set @text_IN = right(@text_IN,len(@text_IN) - @idx)  
    if len(@text_IN) = 0 break  
end 

Split Zeilen in Spalten:

;WITH XMLTable (xmlTag) 
AS 
(
    SELECT CONVERT(XML,'<CSV><champ>' + REPLACE(csvRow,',', '</champ><champ>') + '</champ></CSV>') AS xmlTag 
    FROM @temptable 
) 

SELECT RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[1]','varchar(max)'))) AS Column1,  
     RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[2]','varchar(max)'))) AS Column2, 
     RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[3]','varchar(max)'))) AS Column3,  
     RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[4]','int'))) AS Column4, 
     RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[5]','datetime'))) AS Column5 
FROM XMLTable 
Verwandte Themen