【问题标题】:Return date from value exploded in some columns on SQL Server从 SQL Server 上某些列中爆炸的值返回日期
【发布时间】:2017-04-02 11:42:46
【问题描述】:

我想返回 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

谢谢 皮埃尔

【问题讨论】:

  • 那么,您为什么不与我们分享您迄今为止的尝试?
  • 阅读Is storing a delimited list in a database column really that bad?,您会在其中看到为什么这个问题的答案是绝对是的!
  • @ZoharPeled 可能是这种情况,尽管 OP 不负责数据库的设计。
  • @GiorgosAltanis 是的,这是可能的。即使操作人员没有计划数据库并且无法更改结构,这仍然是需要知道的。
  • @ZoharPeled 我同意 100%

标签: sql sql-server explode


【解决方案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 列。

【讨论】:

  • 很好的参考@ZoharPeled。
  • @GiorgosAltanis 值得付出努力。您可能会对性能提升感到惊讶。
  • 我已经测试了您的查询。它有效,但我有一些表需要使用此查询,我想使用如下查询:SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'myTable' AND TABLE_SCHEMA='dbo' AND COLUMN_NAME != 'id' AND COLUMN_NAME != 'date' 用于检索 COALESCE 函数中的字段列表。谢谢
  • 感谢您的评论;我很高兴该解决方案有效,因此我建议您接受答案(因为它解决了问题)并针对您可能遇到的任何其他问题创建一个新问题。
【解决方案2】:

每个人都应该像 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
...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多