Как объединить 2 таблицы в SQL Server на поле с именами и фамилиями в неизвестном порядке - PullRequest
0 голосов
/ 26 сентября 2018

Интересно, не могли бы вы мне чем-нибудь помочь?Мы получаем агентские счета для работников, которые работали на разных клиентов от нашего имени.Теперь эти Счета имеют фамилию и имя работника в совершенно случайном порядке.Теперь мой пакет служб SSIS импортирует эти счета в базу данных.Я пытаюсь автоматизировать несколько отчетов на основе этих данных.Теперь я хотел бы объединить эти данные счета-фактуры с нашей службой хранения данных и таблицей смен.Только поля, к которым я могу присоединиться, - это Имя и Дата смены.Как я могу присоединить таблицу DW Employee к импортированным счетам, так как имена в таблицах счетов повсюду.Любая хорошая функция SQL, которая может помочь, e.Я пытался присоединиться, используя Concat и Like, но это не сработало.Предложения будут высоко оценены.

enter image description here enter image description here

Спасибо и С уважением

Хуррам

Ответы [ 3 ]

0 голосов
/ 26 сентября 2018

Как уже было сказано, это непростая задача, кроме редизайна.Но, как и SQL_M, я решил попробовать.Предполагая, что dwEmployee является источником записи, я изначально пошел с чем-то похожим на подход SQL_M с этим:

SELECT *
FROM dbo.invoiceTable i
JOIN dwEmployee d
ON 
    (
        d.[DW_personname] LIKE CONCAT('%',SUBSTRING(i.[Name],0,CHARINDEX(' ',i.[name])),' %')
        OR d.[DW_personname] LIKE CONCAT('% ',SUBSTRING(i.[Name],0,CHARINDEX(' ',i.[name])),'%')
    )
AND 
(
    d.[DW_personname] LIKE CONCAT('%',SUBSTRING(i.[Name],CHARINDEX(' ',i.[name])+1,LEN(I.[Name]) - CHARINDEX(' ',i.[name])),' %')
    OR d.[DW_personname] LIKE CONCAT('% ',SUBSTRING(i.[Name],CHARINDEX(' ',i.[name])+1,LEN(I.[Name]) - CHARINDEX(' ',i.[name])),'%')
)

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

В итоге я использовал комбинацию CTE и STRING_SPLIT для возможных совпадений в таблицах.Вы упомянули, что можете присоединиться к Shiftdate, но не сказали точно, как вы хотите, чтобы результаты выглядели, и казалось, что объединение имен было большой проблемой, поэтому я просто сосредоточился на этом.В зависимости от того, какая версия SQL используется для STRING_SPLIT, она может быть недоступна, и в этом случае вам придется использовать другую функцию разбиения, чтобы этот метод работал.(демо здесь http://sqlfiddle.com/#!18/4bd31/2/1)

CREATE TABLE invoiceTable
(
    [Invoice_ID] INT, [ShiftDate] DATE, [Ref_Num] INT, [Name] VARCHAR(200)
)

CREATE TABLE dwEmployee
(
    [Shiftdate] DATE, [DW_personname] VARCHAR(200), [Timesheetserial] VARCHAR(200)
)

INSERT INTO dbo.invoiceTable
VALUES
(807, '2018-09-02',83789315,'ABCD EFGH'), (195, '2018-09-14',83789315,'EFGH ABCD'), (227, '2018-09-15',83789315,'WXYZ EFGH-ABCD'), (246, '2018-09-16',83789315,'JKLM OPQR'),(1398, '2018-09-19',83789315,'STUV IJKKL WXYZ')

INSERT INTO dbo.dwEmployee
VALUES
( '2018-10-22','EFGH ABCD','Z3746543'), ( '2018-10-29','EFIH ABCD','Z3746550'), ( '2018-10-26','EFGH-ABCD WXYZ','Z3746557'),( '2018-10-26','EFGH-ABCD WXYZ','Z3746557')

--my additional insert for testing three-part name

INSERT INTO dbo.dwEmployee
VALUES
( '2018-10-31','WXYZ STUV IJKKL','Z0000000');

--work
WITH nameSplitter AS
(
    SELECT 
        [Invoice_ID], CAST(NULL AS VARCHAR(200)) AS [Timesheetserial], [Value]
    FROM invoiceTable
        CROSS APPLY STRING_SPLIT([Name], ' ')
    UNION ALL 
    SELECT 
        NULL, [Timesheetserial], Value
    FROM dwEmployee
        CROSS APPLY STRING_SPLIT([DW_personname], ' ')
),
potentialMatches AS
(
    SELECT 
        ns1.[Invoice_ID], ns2.[Timesheetserial]
    FROM nameSplitter ns1
    JOIN nameSplitter ns2
        ON ns2.value = ns1.value
    WHERE ns1.[Invoice_ID] IS NOT NULL
        AND ns2.[Timesheetserial] IS NOT NULL
    GROUP BY ns1.[Invoice_ID], ns2.[Timesheetserial]
    HAVING COUNT(ns2.[Timesheetserial]) = (SELECT COUNT([Timesheetserial]) FROM nameSplitter WHERE [Timesheetserial] = ns2.[Timesheetserial] )
)
SELECT i.*, d.* 
FROM potentialMatches p
join dbo.invoiceTable i
    ON P.[Invoice_ID] = I.[Invoice_ID]
JOIN dwEmployee d
    ON p.[Timesheetserial] = d.[Timesheetserial]
0 голосов
/ 26 сентября 2018

Если у вас есть только одно имя и одна фамилия, вы можете попробовать что-то вроде этого:

....
FROM tableA AS A
INNER JOIN tableB AS B
    ON A.Name = B.DW_personname OR A.Name = RIGHT(B.DW_personname, LEN(DW_personname) - CHARINDEX(' ', B.DW_personname) +1) + ' ' + LEFT(B.DW_personname, CHARINDEX(' ', B.DW_personname)) 
0 голосов
/ 26 сентября 2018

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

SELECT LEFT ('John Jackson', CHARINDEX (' ', 'John Jackson')  - 1) AS FirstPart,
       SUBSTRING ('John Jackson', CHARINDEX (' ', 'John Jackson'), LEN ('John Jackson') - CHARINDEX (' ', 'John Jackson') + 1) AS SecondPart

SELECT * 
FROM TableA AS A 
    LEFT JOIN TableB AS B ON A.FirstPart = B.FirstPart AND A.SecondPart = B.SecondPart

   UNION ALL
SELECT * FROM TableA
LEFT JOIN TableB AS B2 ON  A.FirstPart = B2.SecondPart AND A.SecondPart = B2.FirstPart

Удачи в этом!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...