2017-04-02 37 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 
... 
相關問題