2013-03-23 42 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 
相关问题