简体   繁体   English

SQL Server中的字符串串联

[英]String concatenation in SQL server

Consider a situation we have two variables in SQL Server 2005's SP as below, 考虑以下情况,我们在SQL Server 2005 SP中有两个变量,如下所示:

@string1 = 'a,b,c,d'
@string2 = 'c,d,e,f,g'

Is there a solution to get a new string out of that like (@string1 U @string2) without using any loops. 是否有解决方案,可以在不使用任何循环的情况下从类似(@ string1 U @ string2)的字符串中获取新字符串。 ie the final string should be like, 即最后一个字符串应该像

@string3 = 'a,b,c,d,e,f,g'

How about 怎么样

set @string3 = @string1+','+@string2

Sorry, wasn't clear you wanted only unique occurrences. 抱歉,目前还不清楚您是否只希望出现独特的情况。 What version of SQL server are you using? 您正在使用哪个版本的SQL Server? String manipulation functions vary per version. 字符串操作功能因版本而异。

If you don't mind a UDF to split the string, try this: 如果您不介意使用UDF拆分字符串,请尝试以下操作:

CREATE FUNCTION dbo.Split
(
    @RowData nvarchar(2000),
    @SplitOn nvarchar(5)
)  
RETURNS @RtnValue table 
(
    Id int identity(1,1),
    Data nvarchar(100)
) 
AS  
BEGIN 
    Declare @Cnt int
    declare @data varchar(100)
    Set @Cnt = 1

    While (Charindex(@SplitOn,@RowData)>0)
    Begin
       Insert Into @RtnValue (data) 
     Select ltrim(rtrim(Substring(@RowData,1,Charindex(@SplitOn,@RowData)-1)))
             Set @RowData = Substring(@RowData,Charindex(@SplitOn,@RowData)+1,len(@RowData))
         Set @Cnt = @Cnt + 1
    End

    Insert Into @RtnValue (data)
    Select Data = ltrim(rtrim(@RowData))


    Return
END

and the code to use the UDF 以及使用UDF的代码

go
@string1 = 'a,b,c,d'
@string2 = 'c,d,e,f,g'

declare @string3 varchar(200)
set @string3 = ''
select @string3 = @string3+data+',' 
from ( select data,min(id) as Id from dbo.split(@string1+','+@string2,',') 
     group by data ) xx
order by xx.id

print left(@string3,len(@string3)-1)

Two ways you can do that: 有两种方法可以做到这一点:

  • Build a CLR function to do the job for you. 构建CLR函数可以为您完成这项工作。 Move the logic back to .NET code which is much easier platform for string manipulation. 将逻辑移回到.NET代码,这是用于字符串操作的更简单的平台。

  • If you have to use SQL Server, then you will need to: 如果必须使用SQL Server,则需要:

"explode" the two strings into two tables, this function might help: http://blog.logiclabz.com/sql-server/split-function-in-sql-server-to-break-comma-separated-strings-into-table.aspx 将两个字符串“分解”为两个表,此功能可能会有所帮助: http : //blog.logiclabz.com/sql-server/split-function-in-sql-server-to-break-comma-separated-strings-into -table.aspx

Get a unique list of strings from the two tables. 从两个表中获取唯一的字符串列表。 (simple query) (简单查询)

"implode" the two string tables into a variable (http://stackoverflow.com/questions/194852/concatenate-many-rows-into-a-single-text-string) 将两个字符串表“插入”到变量中(http://stackoverflow.com/questions/194852/concatenate-many-rows-into-a-single-text-string)

Found this function dbo.Split in a related answer , which you can use like this: 找到此功能dbo.Split在一个相关的答案中 ,您可以像这样使用:

declare @string1 nvarchar(50) = 'a,b,c,d'
declare @string2 nvarchar(50) = 'c,d,e,f,g'

select * from dbo.split(@string1, ',')

select * from dbo.split(@string2, ',')

declare @data nvarchar(100) = ''

select @data =  @data +  ',' + Data from (
    select Data from dbo.split(@string1, ',')
    union
    select Data from dbo.split(@string2, ',')
) as d

select substring(@data, 2, LEN(@data))

The last SELECT returns 最后的SELECT返回

a,b,c,d,e,f,g

In case you need to do this as a set and not one row at a time. 如果您需要将其作为一组而不是一次一行进行。 Given the following split function: 给定以下拆分功能:

USE tempdb;
GO
CREATE FUNCTION dbo.SplitStrings(@List NVARCHAR(MAX))
RETURNS TABLE
AS
   RETURN ( SELECT Item FROM
       ( SELECT Item = x.i.value('(./text())[1]', 'nvarchar(max)')
         FROM ( SELECT [XML] = CONVERT(XML, '<i>'
         + REPLACE(@List,',', '</i><i>') + '</i>').query('.')
           ) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y
       WHERE Item IS NOT NULL
   );
GO

Then with the following table and sample data, and string variable, you can get all of the results this way: 然后,使用下表和示例数据以及字符串变量,您可以通过这种方式获得所有结果:

DECLARE @foo TABLE(ID INT IDENTITY(1,1), col NVARCHAR(MAX));

INSERT @foo(col) SELECT N'c,d,e,f,g';
INSERT @foo(col) SELECT N'c,e,b';
INSERT @foo(col) SELECT N'd,e,f,x,a,e';

DECLARE @string NVARCHAR(MAX) = N'a,b,c,d';

;WITH x AS
(
    SELECT f.ID, c.Item FROM @foo AS f
    CROSS APPLY dbo.SplitStrings(f.col) AS c
), y AS
(
    SELECT ID, Item FROM x
    UNION
    SELECT x.ID, s.Item
        FROM dbo.SplitStrings(@string) AS s
        CROSS JOIN x
)
SELECT DISTINCT ID, Items = STUFF((SELECT ',' + Item 
    FROM y AS y2 WHERE y2.ID = y.ID 
    FOR XML PATH(''), TYPE).value('.[1]', 'nvarchar(max)'), 1, 1, N'')
FROM y;

Results: 结果:

ID   Items
--   ----------
 1   a,b,c,d,e,f,g
 2   a,b,c,d,e
 3   a,b,c,d,e,f,x

Now that all said, what you really should do is follow the previous advice and store these things in a related table in the first place. 综上所述,您真正应该做的是遵循先前的建议并将这些内容首先存储在相关表中。 You can use the same type of splitting methodology to store the strings separately whenever an insert or update happens, instead of just dumping the CSV into a single column, and your applications shouldn't really have to change the way they're passing data into your procedures. 您可以使用相同类型的拆分方法在发生插入或更新时分别存储字符串,而不仅仅是将CSV转储到单个列中,并且您的应用程序实际上不必更改将数据传递到其中的方式。您的程序。 But it sure will be easier to get the data out! 但这肯定会更容易获得数据!

EDIT 编辑

Adding a potential solution for SQL Server 2008 that is a bit more convoluted but gets things done with one less loop (using a massive table scan and replace instead). 为SQL Server 2008添加一个潜在的解决方案,该解决方案比较麻烦,但是可以减少一个循环(使用大量的表扫描和替换操作)来完成工作。 I don't think this is any better than the solution above, and it is certainly less maintainable, but it is an option to test out should you find you are able to upgrade to 2008 or better (and also for any 2008+ users who come across this question). 我认为这并不比上面的解决方案更好,并且它的维护性肯定较差,但是如果您发现自己能够升级到2008年或更高版本(以及任何具有遇到这个问题)。

SET NOCOUNT ON;

-- let's pretend this is our static table:

CREATE TABLE #x
(
    ID INT IDENTITY(1,1),
    col NVARCHAR(MAX)
);

INSERT #x(col) VALUES(N'c,d,e,f,g'), (N'c,e,b'), (N'd,e,f,x,a,e');

-- and here is our parameter:

DECLARE @string NVARCHAR(MAX) = N'a,b,c,d';

The code: 编码:

DECLARE @sql NVARCHAR(MAX) = N'DECLARE @src TABLE(ID INT, col NVARCHAR(32));
    DECLARE @dest TABLE(ID INT, col NVARCHAR(32));';

SELECT @sql += '
    INSERT @src VALUES(' + RTRIM(ID) + ','''
    + REPLACE(col, ',', '''),(' + RTRIM(ID) + ',''') + ''');'
FROM #x;

SELECT @sql += '
    INSERT @dest VALUES(' + RTRIM(ID) + ','''
    + REPLACE(@string, ',', '''),(' + RTRIM(ID) + ',''') + ''');'
FROM #x;

SELECT @sql += '
    WITH x AS (SELECT ID, col FROM @src UNION SELECT ID, col FROM @dest)
    SELECT DISTINCT ID, Items = STUFF((SELECT '','' + col
     FROM x AS x2 WHERE x2.ID = x.ID FOR XML PATH('''')), 1, 1, N'''')
     FROM x;'

EXEC sp_executesql @sql;
GO
DROP TABLE #x;

This is much trickier to do in 2005 (though not impossible) because you need to change the VALUES() clauses to UNION ALL ... 在2005年,这样做非常棘手(尽管并非不可能),因为您需要将VALUES()子句更改为UNION ALL ...

The following SQL function will convert a comma separated list to a table variable... 以下SQL函数会将逗号分隔的列表转换为表变量...

CREATE FUNCTION [dbo].[udfCsvToTable]( @CsvString VARCHAR( 8000))
-- Converts a comman separated value into a table variable

RETURNS @tbl TABLE( [Value] VARCHAR( 100) COLLATE DATABASE_DEFAULT NOT NULL)

AS BEGIN

DECLARE @Text VARCHAR( 100)

SET @CsvString = RTRIM( LTRIM( @CsvString))
SET @CsvString = REPLACE( @CsvString, CHAR( 9), '')
SET @CsvString = REPLACE( @CsvString, CHAR( 10), '')
SET @CsvString = REPLACE( @CsvString, CHAR( 13), '')

IF LEN( @CsvString) < 1 RETURN

WHILE LEN( @CsvString) > 0 BEGIN

    IF CHARINDEX( ',', @CsvString) > 0 BEGIN

        SET @Text = LEFT( @CsvString, CHARINDEX( ',', @CsvString) - 1)
        SET @CsvString = LTRIM( RTRIM( RIGHT( @CsvString, LEN( @CsvString) - CHARINDEX( ',', @CsvString))))
    END
    ELSE BEGIN

        SET @Text = @CsvString
        SET @CsvString = ''
    END

    INSERT @tbl VALUES( LTRIM( RTRIM( @Text)))
END

RETURN
END

You can then union the two tables together, like so... 然后,您可以将两个表合并在一起,就像这样...

SELECT * FROM udfCsvToTable('a,b,c,d')
UNION   
SELECT * FROM udfCsvToTable('c,d,e,f,g')

Which will give you a result set of: 这将为您提供以下结果集:

abcdefg ABCDEFG

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM