【问题标题】:How to split string using delimiter char using T-SQL?如何使用 T-SQL 使用分隔符字符拆分字符串?
【发布时间】:2011-07-03 01:40:21
【问题描述】:

我在表格的一列中有这个长字符串。我只想获取特定信息:- 我的表结构:-

Col1 = '123'
Col2 = 'AAAAA'
Col3 = 'Clent ID = 4356hy|Client Name = B B BOB|Client Phone = 667-444-2626|Client Fax = 666-666-0151|Info = INF8888877 -MAC333330554/444400800'

我的选择语句是:-

Select col1, col2, col3 from Table01

但在 Col3 中,我只需要“客户名称”的值,即“B B BOB”。

在 Col3 中 -

  • 列分隔符为“|”管道字符(例如“客户端 ID = 4356hy”)

  • 键值分隔符是 '=' 等于符号,带有一个空格(前导和尾随)。

请帮忙。

【问题讨论】:

  • 做好准备,让很多 cmets 知道这种设计有多糟糕 :)
  • 拿起@JNK 的球:这是一个糟糕的设计!但是您仍然可以保存它,如果您更改表结构以仅包含包含所有数据的客户端表的外键...

标签: sql sql-server sql-server-2005 tsql


【解决方案1】:

对于您的具体数据,您可以使用

Select col1, col2, LTRIM(RTRIM(SUBSTRING(
    STUFF(col3, CHARINDEX('|', col3,
    PATINDEX('%|Client Name =%', col3) + 14), 1000, ''),
    PATINDEX('%|Client Name =%', col3) + 14, 1000))) col3
from Table01

编辑 - charindex vs patindex

测试

select col3='Clent ID = 4356hy|Client Name = B B BOB|Client Phone = 667-444-2626|Client Fax = 666-666-0151|Info = INF8888877 -MAC333330554/444400800'
into t1m
from master..spt_values a
cross join master..spt_values b
where a.number < 100
-- (711704 row(s) affected)

set statistics time on

dbcc dropcleanbuffers
dbcc freeproccache
select a=CHARINDEX('|Client Name =', col3) into #tmp1 from t1m
drop table #tmp1

dbcc dropcleanbuffers
dbcc freeproccache
select a=PATINDEX('%|Client Name =%', col3) into #tmp2 from t1m
drop table #tmp2

set statistics time off

时间

CHARINDEX:

 SQL Server Execution Times (1):
   CPU time = 5656 ms,  elapsed time = 6418 ms.
 SQL Server Execution Times (2):
   CPU time = 5813 ms,  elapsed time = 6114 ms.
 SQL Server Execution Times (3):
   CPU time = 5672 ms,  elapsed time = 6108 ms.

PATINDEX:

 SQL Server Execution Times (1):
   CPU time = 5906 ms,  elapsed time = 6296 ms.
 SQL Server Execution Times (2):
   CPU time = 5860 ms,  elapsed time = 6404 ms.
 SQL Server Execution Times (3):
   CPU time = 6109 ms,  elapsed time = 6301 ms.

结论

CharIndex 和 PatIndex 用于 700k 次调用的时间相差在 3.5% 以内,所以我认为无论使用哪个都无关紧要。当两者都可以工作时,我可以互换使用它们。

【讨论】:

  • PATINDEX('%|Client Name =%', col3)CHARINDEX('|Client Name =', col3) 不一样吗,后者不应该比前者快吗?
【解决方案2】:

你需要一个拆分函数:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Create Function [dbo].[udf_Split]
(   
    @DelimitedList nvarchar(max)
    , @Delimiter nvarchar(2) = ','
)
RETURNS TABLE 
AS
RETURN 
    (
    With CorrectedList As
        (
        Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
            + @DelimitedList
            + Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
            As List
            , Len(@Delimiter) As DelimiterLen
        )
        , Numbers As 
        (
        Select TOP( Coalesce(DataLength(@DelimitedList)/2,0) ) Row_Number() Over ( Order By c1.object_id ) As Value
        From sys.columns As c1
            Cross Join sys.columns As c2
        )
    Select CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position
        , Substring (
                    CL.List
                    , CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen     
                    , CharIndex(@Delimiter, CL.list, N.Value + 1)                           
                        - ( CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen ) 
                    ) As Value
    From CorrectedList As CL
        Cross Join Numbers As N
    Where N.Value <= DataLength(CL.List) / 2
        And Substring(CL.List, N.Value, CL.DelimiterLen) = @Delimiter
    )

使用您的拆分功能,然后您将使用交叉应用来获取数据:

Select T.Col1, T.Col2
    , Substring( Z.Value, 1, Charindex(' = ', Z.Value) - 1 ) As AttributeName
    , Substring( Z.Value, Charindex(' = ', Z.Value) + 1, Len(Z.Value) ) As Value
From Table01 As T
    Cross Apply dbo.udf_Split( T.Col3, '|' ) As Z

【讨论】:

【解决方案3】:

很糟糕,但你可以尝试使用

select
SUBSTRING(Table1.Col1,0,PATINDEX('%|%=',Table1.Col1)) as myString
from
Table1

不过,这段代码可能不是 100% 正确的。需要调整

【讨论】:

    【解决方案4】:

    您只需对 col3 中的字符串执行 SUBSTR ....

        Select col1, col2, REPLACE(substr(col3, instr(col3, 'Client Name'), 
        (instr(col3, '|', instr(col3, 'Client Name')  -
        instr(col3, 'Client Name'))
        ),
    'Client Name = ',
    '')
        from Table01 
    

    是的,由于原始问题中所述的原因,这是一个糟糕的数据库设计

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-13
      • 2011-12-26
      • 1970-01-01
      • 2012-02-14
      • 2021-06-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多