如何创建显示拆分数据中的行的视图

时间:2016-11-28 19:44:04

标签: sql-server

用表格作为:

Name    Num     Value
----------------------
Peter   10      10
Mary    10,15   5,10
John    5,20    10,20

如何以带有View的后续表格获得结果?

Name   Num   Value
------------------
Peter  10     10
Mary   10      5
Mary   15     10
John    5     10
John   20     20

注意Mary和John有多个数据(以逗号分隔)。

我有一个函数来进行单元格的拆分并返回一个表,但只是针对特定的行和单元格,要从所有表中迭代?

有条件的信息:

SELECT NAM.NAME, Data AS NUM, VAL.VALUE
  FROM dbo.Split((SELECT NUM FROM t1 WHERE LineNum = 2), ','))
CROSS APPLY (
    SELECT Id As Id1, Data AS VALUE
          FROM dbo.Split((SELECT VALUE FROM t1 WHERE LineNum = 2), ','))
    ) AS VAL
CROSS APPLY (
    SELECT NAME FROM t1 WHERE LineNum = 2
    ) AS NAM
WHERE Id = Id1

注意:LineNum是来自t1的行号

来自t1的第二行(玛丽| 10,15 | 5,10)

Previous Function将表格返回为:

Name   Num   Value
------------------
Mary    10    5
Mary    15   10

单元格中的拆分函数(10,15)返回:

Id   Data
-----------
1    10
2    15

===============================================

我的分裂功能:

CREATE FUNCTION [dbo].[Split]
(
    @String NVARCHAR(4000),
    @Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
    WITH Split(stpos,endpos)
    AS(
        SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos
        UNION ALL
        SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1)
            FROM Split
            WHERE endpos > 0
    )
    SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
        'Data' = SUBSTRING(@String,stpos,COALESCE(NULLIF(endpos,0),LEN(@String)+1)-stpos)
    FROM Split
)

1 个答案:

答案 0 :(得分:3)

Declare @YourTable table (Name varchar(50), Num varchar(50), Value  varchar(50))
Insert into @YourTable values
('Peter','10',  '10'),
('Mary','10,15','5,10'),
('John','5,20', '10,20')

Select A.Name
      ,B.*
 From  @YourTable A
 Cross Apply ( 
                Select Num   = A.RetVal
                      ,Value = B.RetVal
                From (
                        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(A.Num,',','</x><x>')+'</x>' as xml).query('.')) as A 
                        Cross Apply x.nodes('x') AS B(i)
                ) A
                Join (
                        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(A.Value,',','</x><x>')+'</x>' as xml).query('.')) as A 
                        Cross Apply x.nodes('x') AS B(i)
                ) B on A.RetSeq=B.RetSeq
             ) B

返回

Name    Num Value
Peter   10  10
Mary    10  5
Mary    15  10
John    5   10
John    20  20
  

编辑 - UDF的另一个选项

Select A.Name
      ,B.*
 From  @YourTable A
 Cross Apply ( 
                Select Num   = A.RetVal
                      ,Value = B.RetVal
                From [dbo].[udf-Str-Parse-8K](A.Num,',') A
                Join [dbo].[udf-Str-Parse-8K](A.Value,',') B 
                  on A.RetSeq=B.RetSeq
             ) B

最快的UDF

CREATE FUNCTION [dbo].[udf-Str-Parse-8K] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
    with   cte1(N)   As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
           cte2(N)   As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a,cte1 b,cte1 c,cte1 d) A ),
           cte3(N)   As (Select 1 Union All Select t.N+DataLength(@Delimiter) From cte2 t Where Substring(@String,t.N,DataLength(@Delimiter)) = @Delimiter),
           cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(@Delimiter,@String,s.N),0)-S.N,8000) From cte3 S)

    Select RetSeq = Row_Number() over (Order By A.N)
          ,RetVal = Substring(@String, A.N, A.L) 
    From   cte4 A
);
--Much faster than str-Parse, but limited to 8K
--Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')