通过整理为包含定界数据的单个列,将两个包含定界数据的sql列组合在一起

时间:2019-04-12 15:58:57

标签: tsql sql-server-2012

我有两个sql列,每个列都包含要分隔的数据,我希望将它们整理并合并为一个分隔的列。列中的项目数对于每一行都是可变的。但是,每行两列之间始终会有匹配的项目数。例如...

*******************************
ORIGINAL SQL TABLE
*******************************
value          *    unit
*******************************
4 ; 5          *   mg ; kg
50             *   mg
7.5 ; 325      *   kg ; mg
100 ; 1.5 ; 50 *   mg ; g ; mg
********************************

*********************************
DESIRED SQL RESULT
*********************************
value-unit
*********************************
4 mg; 5 kg
50 mg
7.5 kg; 325 mg
100 mg; 1.5 g; 50 mg
*********************************

如何使用T-SQL执行此操作?我正在使用SQL Server 2012

2 个答案:

答案 0 :(得分:0)

STRING_SPLIT是最新的解决方案。如果您使用的不是2016年或更高版本,并且无法将数据库兼容性设置为该版本或更高版本,则可以使用xml:

我在原始表中添加了一个身份,以便通过-来订购商品

SELECT splitNumbers.splitNumber,
       splitValues.splitValue,
       splitNumbers.splitNumber + ' ' + splitValues.splitValue AS combined
FROM
(
    SELECT --numbers,
        LTRIM(RTRIM(m.n.value('.[1]', 'varchar(8000)'))) AS splitNumber,
        ROW_NUMBER() OVER (ORDER BY id) AS rn
    FROM
    (
        SELECT id,
               CAST('<XMLRoot><RowData>' + REPLACE(numbers, ' ; ', '</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS xmlNumbers
        FROM #x
    ) fee
        CROSS APPLY xmlNumbers.nodes('/XMLRoot/RowData') m(n)
) splitNumbers
    INNER JOIN
    (
        SELECT LTRIM(RTRIM(m.v.value('.[1]', 'varchar(8000)'))) AS splitValue,
               ROW_NUMBER() OVER (ORDER BY id) AS rn
        FROM
        (
            SELECT id,
                   CAST('<XMLRoot><RowData>' + REPLACE(units, ' ; ', '</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS xmlUnits
            FROM #x
        ) fee
            CROSS APPLY xmlUnits.nodes('/XMLRoot/RowData') m(v)
    ) splitValues
        ON splitNumbers.rn = splitValues.rn;

This gives the following results:
================================
splitNumber splitValue  combined
4           mg           4 mg
5           kg           5 kg
50          mg           50 mg
7.5         kg           7.5 kg
325         mg           325 mg
100         mg           100 mg
1.5         g            1.5 g
50          mg           50 mg

答案 1 :(得分:0)

仅使用公用表表达式,我们也可以得到所需的结果,如下所示:-

首先让我们设置数据

declare @original table(
[value] varchar(250), 
[unit] varchar(250)
)
insert into @original values 
('4 ; 5','mg ; kg    '),
('50','mg        '                ),
('7.5 ; 325','kg ; mg    '        ),
('100 ; 1.5 ; 50 ','mg ; g ; mg'  )

现在,让我们构建公用表表达式:-

;with cte as (
    select o.[value]+';' [value],o.[unit]+';' [unit],row_number() over (ORDER BY (Select 0)) [row]   from @original o
),cte2 as (
    select *
    ,1 [ValueStart],CHARINDEX(';',[value]) [ValueEnd]
    ,1 [UnitStart],CHARINDEX(';',[unit]) [UnitEnd]
     from cte
),cte3 as (
    select * from cte2
    union all 
    select [value],[unit],[row]
        ,[ValueEnd]+1 [ValueStart],CHARINDEX(';',[value],[ValueEnd]+1) [ValueEnd] 
        ,[UnitEnd]+1 [UnitStart],CHARINDEX(';',[unit],[UnitEnd]+1) [UnitEnd] 
    from cte3 where [UnitEnd]>0
),cte4 as (
    select *,row_number() over (partition by [row] order by [row]) [subRow]
    , rtrim(ltrim(substring([unit],[UnitStart],[UnitEnd]-[UnitStart])))  [subUnit] 
    , rtrim(ltrim(substring([value],[ValueStart],[ValueEnd]-[ValueStart])))  [subValue] 
    from cte3
    where [UnitEnd]>0
),cte5 as (
    select subRow,[row],[subValue],[subUnit],cast([subValue]+' '+[subUnit] as varchar(max)) [ValueUnit] from cte4 where subRow=1
    union all
    select cte4.subRow,cte4.[row],cte4.[subUnit],cte4.[subValue]
        ,cte5.[ValueUnit]+';'+ cte4.[subValue]+' '+cte4.[subUnit] [ValueUnit] 
            from cte4
        inner join cte5 on (cte5.subRow+1)=cte4.subRow and cte5.[row]=cte4.[row]
),cte6 as (
    select *,row_number() over (partition by [row] order by subRow desc) [selected] from cte5
)
select ValueUnit from cte6
where [selected]=1
order by [row] 

结果如下:-

ValueUnit
============
4 mg;5 kg 
50 mg  
7.5 kg;325 mg 
100 mg;1.5 g;50 mg