Построение наборов данных из нескольких многозначных записей с использованием применений с отсутствующими значениями - PullRequest
0 голосов
/ 31 августа 2018

У меня есть база данных SQL Server 2012, которая была импортирована из многозначной среды, что вызывает у меня больше головной боли, чем я хочу сосчитать, однако это то, что есть, и мне приходится с ней работать.

Я пытаюсь создать набор данных, используя эти многозначные записи, но столкнулся с камнем преткновения. Это мой сценарий

У меня есть пользовательский разделитель строки TVF, который разбивает строку «Test, String» на

Rowno | Item
------+---------
1     | Test
2     | String

У меня есть следующие данные:

Таблица клиентов

Ref | Names     | Surname   | DOB                 | IdNo
----+-----------+-----------+---------------------+------    
123 |John,Sally |Smith     | DOB1,DoB2            | 45,56
456 |Dave,Paul  |Jones,Dann| DOB1,DOB2            | 98
789 |Mary,Moe,Al|Lee       | DOB1                 | NULL

Мне нужно создать набор данных, который выглядит следующим образом:

Ref | Names     | Surname   | DOB                 | IdNo
----+-----------+-----------+---------------------+------    
123 | John      | Smith     | DOB1                | 45
123 | Sally     | Smith     | DOB2                | 56
456 | Dave      | Jones     | DOB1                | 98
456 | Paul      | Dann      | DOB2                |
789 | Mary      | Lee       | DOB1                | 
789 | Moe       | Lee       |                     | 
789 | Al        | Lee       |                     |

Раньше для решения подобных проблем я решал этот вопрос следующим образом:

SELECT 
    Ref
    , SplitForenames.ITEM names
    , SplitSurname.ITEM Surname
    , SplitDOB.ITEM dob
    , SplitNI.ITEM ID
FROM
    Clients
CROSS APPLY 
    dbo.udf_SplitString(Names, ',') SplitForenames
OUTER APPLY 
    dbo.udf_SplitString(Surname, ',') SplitSurname
OUTER APPLY 
    dbo.udf_SplitString(DOB, ',') SplitDOB
OUTER APPLY 
    dbo.udf_SplitString(ID, ',') SplitNI
WHERE
    SplitSurname.RowNo = SplitForenames.RowNo
    AND SplitDOB.RowNo = SplitForenames.RowNo
    AND SplitNI.RowNo = SplitForenames.RowNo    
ORDER BY 
    REF;

Однако из-за того, что есть примеры различий между количеством фамилий в именах и отсутствующими полями DOB и ID, я не могу сопоставить их таким образом.

Мне нужно сопоставить, где есть совпадение, в противном случае не указывать DOB и ID и использовать первый экземпляр фамилии. Я просто застрял в том, как этого добиться.

У каждого есть какие-либо предложения относительно того, как я могу создать свой требуемый набор данных из исходного источника.

Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Я не могу найти условие разделения столбца DOB или нет. Однако: с функцией Split SpliF , как показано ниже:

CREATE FUNCTION SplitF(@str AS NVARCHAR(max))
RETURNS @People TABLE
(Rowno INT,Item NVARCHAR(10))
AS
BEGIN
    DECLARE @i INT, @pos INT
    DECLARE @subname NVARCHAR(max)
    SET @I = 0;
    WHILE(LEN(@str)>0)
    BEGIN
        SET @pos = CHARINDEX(',',@str)
        IF @pos = 0 SET @pos = LEN(@str)+1
        SET @subname = SUBSTRING(@str,1,@pos-1)
        SET @str = SUBSTRING(@str, @pos+1, len(@str))
        SET @i = @i + 1
        INSERT INTO @People VALUES (@i, @subname)
    END
    RETURN
END
GO
select * from SplitF('test,my,function')

Rowno       Item
----------- ----------
1           test
2           my
3           function

и основные данные:

select Ref, Names, Surname, DOB, IdNo into #clients
from (  select 123 as Ref, 'John,Sally' as Names, 'Smith' as Surname,
                 'DOB1,DOB2' as DOB, '45,56' as IdNo
        union all select 456, 'Dave,Paul','Jones,Dann','DOB1,DOB2', '98'
        union all select 789, 'Mary,Moe,Al', 'Lee', 'DOB1', NULL) A

select * from #clients

Ref         Names       Surname    DOB       IdNo
----------- ----------- ---------- --------- -----
123         John,Sally  Smith      DOB1,DOB2 45,56
456         Dave,Paul   Jones,Dann DOB1,DOB2 98
789         Mary,Moe,Al Lee        DOB1      NULL

используя приведенный ниже код, вы получите такие результаты:

select
    Ref,
    RTrim(S_NAM.Item) as Names,
    coalesce(S_SURNAM.Item,S_SURNAM_LAST.Item) AS Surname,
    coalesce(split_dob.Item, '') as DOB,
    coalesce(split_IdNo.Item,'') as IdNo
from
    #clients MAIN
    outer apply(select Rowno, Item from SplitF(MAIN.Names)) as S_NAM
    outer apply(select top 1 Item from SplitF(MAIN.Surname) where Rowno = S_NAM.Rowno) as S_SURNAM
    outer apply(select top 1 Item from SplitF(MAIN.Surname) order by Rowno desc) as S_SURNAM_LAST
    outer apply(select top 1 Item from SplitF(MAIN.IdNo) where Rowno = S_NAM.Rowno) as split_IdNo
    outer apply(select top 1 Item from SplitF(MAIN.DOB) where Rowno = S_NAM.Rowno) as split_dob
order by MAIN.Ref, S_NAM.Rowno

Ref         Names      Surname    DOB        IdNo
----------- ---------- ---------- ---------- ----------
123         John       Smith      DOB1       45
123         Sally      Smith      DOB2       56
456         Dave       Jones      DOB1       98
456         Paul       Dann       DOB2       
789         Mary       Lee        DOB1       
789         Moe        Lee                   
789         Al         Lee  
0 голосов
/ 31 августа 2018

Я думаю, что вы можете справиться с этим, используя подзапросы и выполняя RowNo сравнение до OUTER APPLY:

FROM Clients c CROSS APPLY
     dbo.udf_SplitString(Names, ',') SplitForenames OUTER APPLY 
     (SELECT . . .
      FROM dbo.udf_SplitString(Surname, ',') SplitSurname
      WHERE SplitSurname.RowNo = SplitForenames.RowNo
     ) SplitSurname OUTER APPLY
     (SELECT . . .
      FROM dbo.udf_SplitString(DOB, ',') SplitDOB
      WHERE SplitDOB.RowNo = SplitForenames.RowNo
     ) SplitDOB OUTER APPLY
     (SELECT . . .
      FROM dbo.udf_SplitString(DOB, ',') SplitNI
      WHERE SplitNI.RowNo = SplitForenames.RowNo
     ) SplitNI
...