T-SQL Parse分隔数据

时间:2014-04-09 01:19:42

标签: sql sql-server tsql

我在解析一些我得到的数据时遇到了一些问题,其格式如下:

1. FREE_AGENT    "10710,|9452,"
2. FREE_AGENT    "11381,|2918,"
3. FREE_AGENT    "10220,|"
4. FREE_AGENT    "9625,|"
5. FREE_AGENT    "11213,11225,11193,|"

,|分隔符之前的所有内容都被视为播放器添加,,|分隔符之后的所有内容都被视为丢弃。

理想情况下,我希望将其解析为如下所示的行:

1. FREE_AGENT    ADD    "10710"
1. FREE_AGENT    DROP    "9452"
2. FREE_AGENT    ADD    "11381"
2. FREE_AGENT    DROP    "2918"
3. FREE_AGENT    ADD    "10220"
4. FREE_AGENT    ADD    "9625"
5. FREE_AGENT    ADD    "11213"
5. FREE_AGENT    ADD    "11225"
5. FREE_AGENT    ADD    "11193"

任何帮助将不胜感激。我有基本的t-sql字符串分割器,但没有得到很多运气,如

CREATE FUNCTION split(
    @delimited NVARCHAR(MAX),
    @delimiter NVARCHAR(100)
) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
    DECLARE @xml XML
    SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'
    INSERT INTO @t(val)
    SELECT  r.value('.','varchar(MAX)') as item
    FROM  @xml.nodes('/t') as records(r)
    RETURN
END

2 个答案:

答案 0 :(得分:0)

我喜欢使用动态sql来解析字符串。您可以使用Union All Select(在其他解析中)替换分隔符以使其工作:

-- load your test data
declare @YourTable table(AGENT varchar(10),STRING varchar(50))
insert into @YourTable values
    ('FREE_AGENT','10710,|9452,'),
    ('FREE_AGENT','11381,|2918,'),
    ('FREE_AGENT','10220,|'),
    ('FREE_AGENT','9625,|'),
    ('FREE_AGENT','11213,11225,11193,|')

-- create dynamic query to return parsed STRING value
-- with associated AGENT and ADD_DROP value
declare @sql varchar(max)
set @sql = ''
select @sql = @sql + '
select
    ''' + AGENT + ''' AGENT,
    ''' + ADD_DROP + ''' ADD_DROP,
    ' + replace(STRING,',','
union all
select
    ''' + AGENT + ''' AGENT,
    ''' + ADD_DROP + ''' ADD_DROP,') + '
union all'
from    (
        select
            AGENT,
            'ADD' ADD_DROP,
            replace(left(STRING,charindex('|',STRING)),',|','') STRING
        from @YourTable
        where replace(left(STRING,charindex('|',STRING)),'|','') <> ''
        union all
        select
            AGENT,
            'DROP' ADD_DROP,
            replace(replace(right(STRING,charindex('|',
                reverse(STRING))),'|','') + '|',',|','') STRING
        from @YourTable
        where replace(right(STRING,charindex('|',reverse(STRING))),'|','') <> ''
        ) q

-- remove last union all
set @sql = replace(@sql + '|','union all|','')

-- return results
exec(@sql)

答案 1 :(得分:0)

因为你只有一个“,|”用于将ADD与DROP分开的分隔符,您可以在CTE中执行此操作,以便它们返回两个不同的列,一个ADD的CSV列和一个DROP的CSV列。然后你可以用标准分割器拆分它们,使用UNION ALL将一列的拆分与另一列的拆分结合起来。

示例:
(请注意,下面的示例使用了一个名为SQL#(SQLsharp)的SQLCLR库,我是作者。此处使用的拆分函数可以在免费版中获得。如果您愿意,还有其他几种方法可以正确拆分SQL Server中的CSV,我已在此answer

中注明了它们
DECLARE @Data TABLE (AgentID INT NOT NULL PRIMARY KEY,
                     Agent NVARCHAR(50),
                     Actions VARCHAR(500))

INSERT INTO @Data VALUES (1, N'FREE_AGENT', '10710,|9452,')
INSERT INTO @Data VALUES (2, N'FREE_AGENT','11381,|2918,')
INSERT INTO @Data VALUES (3, N'FREE_AGENT','10220,|')
INSERT INTO @Data VALUES (4, N'FREE_AGENT','9625,|')
INSERT INTO @Data VALUES (5, N'FREE_AGENT','11213,11225,11193,|')
INSERT INTO @Data VALUES (6, N'FREE_AGENT','9633,|342,54545,')

;WITH SplitActions AS
(
    SELECT sd.AgentID,
           sd.Agent,
           sd.Actions,
           CHARINDEX(',|', sd.Actions) AS [DelimiterLocation]
    FROM   @Data sd
),
SplitValues AS
(
    SELECT sa.AgentID,
           sa.Agent,
           SUBSTRING(sa.Actions, 1, (sa.DelimiterLocation - 1)) AS [Adds],
           SUBSTRING(sa.Actions, (sa.DelimiterLocation + 2), 500) AS [Drops]
    FROM   SplitActions sa
)
SELECT  sv.AgentID, sv.Agent, N'ADD' AS [Action], addvals.SplitVal AS [ID]
FROM    SplitValues sv
CROSS APPLY SQL#.String_Split4k(sv.Adds, N',', 2) addvals
UNION ALL
SELECT  sv.AgentID, sv.Agent, N'DROP' AS [Action], dropvals.SplitVal AS [ID]
FROM    SplitValues sv
CROSS APPLY SQL#.String_Split4k(sv.Drops, N',', 2) dropvals
ORDER BY [AgentID] ASC, [Action] ASC

输出

AgentID  Agent       Action   ID
1        FREE_AGENT  ADD      10710
1        FREE_AGENT  DROP     9452
2        FREE_AGENT  ADD      11381
2        FREE_AGENT  DROP     2918
3        FREE_AGENT  ADD      10220
4        FREE_AGENT  ADD      9625
5        FREE_AGENT  ADD      11213
5        FREE_AGENT  ADD      11225
5        FREE_AGENT  ADD      11193
6        FREE_AGENT  ADD      9633
6        FREE_AGENT  DROP     342
6        FREE_AGENT  DROP     54545