2017-04-02 76 views
0

我想在SQL Server上返回每个由斜杠分解的字符串的日期。从SQL Server的某些列中展开值的返回日期

我的数据库表:

id | date  | col1  | col2  | col3 | col4 
---+------------+-------------+-----------+-------+------------ 
1 | 2017-04-02 | /txt1/txt2 |   |  | 
2 | 2017-04-03 |    | /txt1/txt4|  | 
3 | 2017-04-04 |    |/txt2/txt3 |  | 
4 | 2017-04-05 |    |/txt4  |  |/txt5/txt6 

结果想:

2017-04-02 txt1 
2017-04-02 txt2 
2017-04-03 txt1 
2017-04-03 txt4 
2017-04-04 txt2 
2017-04-04 txt3 
2017-04-05 txt4 
2017-04-05 txt5 
2017-04-05 txt6 

谢谢 皮埃尔

+2

那么,你为什么不跟我们分享你到目前为止试过吗? –

+0

阅读[在数据库列中存储分隔列表真的不好吗?](http://stackoverflow.com/questions/3653462/is-storing-a-delimited-list-in-a-database-column-really-那么你会看到很多原因,为什么这个问题的答案是**绝对是!** –

+0

@ZoharPeled它可以是这种情况,但OP不负责数据库的设计。 –

回答

1

假设你不能使用STRING_SPLIT() function(可从SQL Server 2016)首先需要标记varchar列的函数。网络上有数百个,我尽管选择最适合和最好的测试,但我还是留给你。

对于我的例子中,我将与this去,这对您的样本工程:

CREATE FUNCTION [dbo].[fnSplitString] 
( 
    @string NVARCHAR(MAX), 
    @delimiter CHAR(1) 
) 
RETURNS @output TABLE(splitdata NVARCHAR(MAX) 
) 
BEGIN 
    DECLARE @start INT, @end INT 
    SELECT @start = 1, @end = CHARINDEX(@delimiter, @string) 
    WHILE @start < LEN(@string) + 1 BEGIN 
     IF @end = 0 
      SET @end = LEN(@string) + 1 

     INSERT INTO @output (splitdata) 
     VALUES(SUBSTRING(@string, @start, @end - @start)) 
     SET @start = @end + 1 
     SET @end = CHARINDEX(@delimiter, @string, @start) 

    END 
    RETURN 
END 

运用分割功能

select t.date, x.splitdata 
from test t 
cross apply dbo.fnSplitString(
    coalesce(col1, '') + coalesce(col2, '') 
    + coalesce(col3, '') + coalesce(col4, '') 
, '/') x 
where coalesce(x.splitdata, '') <> '' 

rextester demo

注意,在演示中,我使用Id列而不是date列。

+0

Aaron Bertrand的[分割字符串正确的方式 - 或下一个最好的方式。](https://sqlperformance.com/2012/07/t-sql-queries/split-strings) –

+0

伟大的参考@ZoharPeled。 –

+0

@GiorgosAltanis非常值得努力。你可能会对性能增益感到惊讶。 –

0

与Zohar Peled相关的每个人都应该拥有良好的分割/解析功能。

另一种选择,如果你不能使用(或想要)的UDF。

Select A.Date 
     ,C.RetVal 
From YourTable A 
Cross Apply (values (col1),(col2),(col3),(col4)) B (Value) 
Cross Apply (
       Select RetSeq = Row_Number() over (Order By (Select null)) 
         ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)'))) 
       From (Select x = Cast('<x>' + replace((Select replace(B.Value,'/','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
       Cross Apply x.nodes('x') AS B(i) 
      ) C 
Where C.RetVal is not null 

返回

Date  RetVal 
2017-04-02 txt1 
2017-04-02 txt2 
2017-04-03 txt1 
2017-04-03 txt4 
... 
相关问题