SQL Server:比较两个表中的两列

时间:2017-08-14 17:50:19

标签: sql-server sql-server-2012

我有两张桌子(来自两个不同的系统)跟踪员工的情况。小时。在两个表中,员工输入日期和小时。我需要创建一个显示差异的审计报告。报告需要显示所有列,如果存在不匹配,则显示空/不匹配。一个表可能有比其他表更多/更少的条目,甚至重复条目,我需要捕获它(同一天两个条目在一个表中相同的小时数)。两个表都有可以连接的UserID。

如果根据日期和时间匹配,则显示所有值。 如果基于小时数不匹配,则在不匹配时显示null或不匹配。 如果有重复的条目,如下图所示,则匹配第一个条目并将第二个条目报告为空或不匹配。

我尝试根据UserID,日期和小时加入表格,但无法分辨出不匹配的来源。

表A:

enter image description here

表B:

enter image description here

左边加入UserID,日期和小时

enter image description here

1 个答案:

答案 0 :(得分:1)

SET NOCOUNT ON;

declare @table1 table
(
    userid int,
    entry_date date,
    [hours] varchar(10)
)

declare @table2 table
(
    userid int,
    entry_date datetime,
    [hours] varchar(10)
)

INSERT INTO @table1
select 1,'8/14/2017','10:00'
INSERT INTO @table1
select 2,'8/14/2017','5:00'
INSERT INTO @table1
select 2,'8/14/2017','5:00'
INSERT INTO @table1
select 2,'8/14/2017','5:00'
INSERT INTO @table1
select 2,'8/14/2017','5:00'
INSERT INTO @table1
select 3,'8/14/2017','5:00'
INSERT INTO @table1
select 3,'8/14/2017','6:00'
INSERT INTO @table1
select 3,'8/14/2017','6:00'
INSERT INTO @table1
select 3,'8/14/2017','6:00'

INSERT INTO @table2
select 1,'8/14/2017','10:00'
INSERT INTO @table2
select 2,'8/14/2017','8:00'
INSERT INTO @table2
select 3,'8/14/2017','6:00'
INSERT INTO @table2
select 4,'8/14/2017','2:00'
INSERT INTO @table2
select 1,'8/14/2017','10:00'
INSERT INTO @table2
select 3,'8/14/2017','6:00'

;WITH CTE_TABLE1 AS
(
    select  t.userid as userid, CAST(t.entry_date as DATE) as entry_date,   t.[hours] as [hours], 
            ROW_NUMBER() OVER(PARTITION BY t.userid, t.entry_date, t.[hours] ORDER BY t.[Hours]) as rnk
    from @Table1 t
), CTE_TABLE2 AS
(
    select  t.userid as userid, CAST(t.entry_date as DATE) as entry_date,   t.[hours] as [hours], 
            ROW_NUMBER() OVER(PARTITION BY t.userid, t.entry_date, t.[hours] ORDER BY t.[Hours]) as rnk
    from @Table2 t
), CTE_MATCHES AS
(
    select  t1.userid as userid, t1.entry_date as entry_date, t1.[hours] as [hours], t1.rnk
    from CTE_TABLE1 t1
    inner join CTE_TABLE2 t2
        on (t1.userid = t2.userid AND t1.entry_date = t2.entry_date AND t1.[hours] = t2.[hours] AND t1.rnk = t2.rnk)
),CTE_MATCH_DUPLICATES AS
(
    select 'Table1MatchDuplicate' as ErrorType, *
    from
    (
        select t.*
        from (select userid, entry_date, [hours], max(rnk) as rnk from CTE_MATCHES group by userid, entry_date, [hours]) m
        inner join CTE_TABLE1 t
            on (t.userid = m.userid AND t.entry_date = m.entry_date AND t.[hours] = m.[hours] AND t.rnk > m.rnk)
    )q
    UNION ALL
    select 'Table2MatchDuplicate' as ErrorType, *
    from
    (
        select t.* 
        from (select userid, entry_date, [hours], max(rnk) as rnk from CTE_MATCHES group by userid, entry_date, [hours]) m
        inner join CTE_TABLE2 t
            on (t.userid = m.userid AND t.entry_date = m.entry_date AND t.[hours] = m.[hours] AND t.rnk > m.rnk)
    )q
)
, CTE_Table1_UNMATCHED AS
(   
    select t.userid, t.entry_date, t.[hours] 
    from @Table1 t
    left outer join CTE_MATCHES m
        on (t.userid = m.userid AND CAST(t.entry_date as DATE) = m.entry_date AND t.[hours] = m.[hours])
    where m.userid is null
), CTE_Table2_UNMATCHED AS
(   
    select t.userid, t.entry_date, t.[hours] 
    from @Table2 t
    left outer join CTE_MATCHES m
        on (t.userid = m.userid AND CAST(t.entry_date as DATE) = m.entry_date AND t.[hours] = m.[hours])
    where m.userid is null
)
select null as ErrorType, userid, entry_date, [hours] from CTE_MATCHES
UNION ALL
select 'Table1Mismatch' as ErrorType, userid, entry_date, [hours] from CTE_Table1_UNMATCHED
UNION ALL
select 'Table2Mismatch' as ErrorType, userid, entry_date, [hours] from CTE_Table2_UNMATCHED
UNION ALL
select ErrorType, userid, entry_date, [hours] from CTE_MATCH_DUPLICATES
order by ErrorType

http://rextester.com/UDG95824

如果您需要查找没有匹配项的重复项:

,CTE_Table1_Unmatched_Duplicates AS
(
    select userid, entry_date, [hours]
    from CTE_Table1_UNMATCHED
    group by userid, entry_date, [hours]
    having count(*) > 1
),CTE_Table2_Unmatched_Duplicates AS
(
    select userid, entry_date, [hours]
    from CTE_Table2_UNMATCHED
    group by userid, entry_date, [hours]
    having count(*) > 1
)
...
UNION
select 'Table1UnmatchedDuplicates' as ErrorType, userid, entry_date, [hours] from CTE_Table1_Unmatched_Duplicates
UNION
select 'Table2UnmatchedDuplicates' as ErrorType, userid, entry_date, [hours] from CTE_Table2_Unmatched_Duplicates

http://rextester.com/KEJJF79330