2013-03-23 67 views
10

我有逗號等分離ID列表:如何將逗號分隔的NVARCHAR轉換爲SQL Server 2005中的表記錄?

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

我想將它們轉換爲一個表中的記錄(到一個臨時表),如

#tempTable 

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

有可能與功能,一個表值?

爲什麼我要這樣?我想與另一個表(一個或多個)等作爲用於INNER JOIN條款(到存儲過程):

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

我不能使用IN因爲我將使用它接受類型NVARCHAR的參數存儲過程。該參數將提供ID列表。

謝謝

+0

[車削逗號分隔字符串轉換成各個行]的可能重複(http://stackoverflow.com/que stions/5493510 /車削-A-逗號分隔的字符串 - 到 - 個人-行)[在SQL分割字符串](的 – 2013-03-23 10:25:15

+0

可能重複http://stackoverflow.com/questions/2647/split-string-in-sql ) – 2013-03-23 10:52:00

回答

18

separate comma separated values and store in table in sql server可能的複製。使用XML

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 

入住其他方式的要求:

請嘗試從Comma-Delimited Value to Table精確的一個

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

XML拆分比循環更慢3倍以上! – 2017-08-29 11:19:40

+0

如果在逗號分隔字符串中有數千個值,即在@param中,則XML分割將更快,然後循環一次,即@param – Gurunadh 2017-10-25 14:43:06

2

我發現並不需要一個函數或XML技巧的方法。

基本上你變換串入一個單一的INSERT語句爲臨時表。
然後可以用於進一步處理。

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; 

此方法最多可使用1000個值。
因爲1000是行值表達式的最大限制。
或者直到達到@InsertStatement的varchar限制。

而且,斯圖爾特安斯沃思指出。
由於此方法使用EXEC,請謹慎使用代碼注入,並且不要將其用於基於未經驗證的用戶輸入的字符串。

+0

嘗試此行: DECLARE @TEXT varchar(max)='1,17,25,44,46 ,67,88); DELETE FROM #tempTable WHERE(1 = 1; SQL注入雖然不太可能用這種方法 – 2016-03-24 11:05:32

+0

我很抱歉,我認爲你誤解了我把DELETE語句放入文本字符串,這將由你的exec語句執行THat是一種經典的SQL注入形式;具有足夠的權限,有人可以做各種惡作劇(如刪除數據庫,創建用戶)...... – 2016-03-24 11:21:23

+0

同樣,這不太可能,但這是一種避免的設計模式 – 2016-03-24 11:22:30

0

完成解答,您也可以使用CSV字符串中存儲多個值多列:

--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' 

斯普利特CSV文件導入行:

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 

分離行成列:

;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 
相關問題