【问题标题】:Get all employees that belong to exact same location list as the passed in employee获取与传入的员工属于完全相同位置列表的所有员工
【发布时间】:2021-04-05 22:25:25
【问题描述】:

我有一张桌子叫EmployeeLocationAssn:

CREATE TABLE EmployeeLocationAssn (
[EmployeeLocationAssnId] [int]  IDENTITY(1,1) NOT NULL, 
[EmployeeId] [int] NOT NULL,
[LocationId] [int] NOT NULL
)

此表包含员工及其相关位置的数据。

INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (1, 1)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (1, 2)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (2, 1)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (2, 2)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (3, 1)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (3, 2)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (4, 1)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (4, 2)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (4, 3)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (4, 4)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (5, 3)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (5, 4)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (6, 1)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (6, 2)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (6, 3)
INSERT INTO EmployeeLocationAssn (EmployeeId, LocationId) VALUES (6, 4)

我想获取与传入的员工 ID 具有完全相同位置列表的所有员工。

示例: 如果用户通过EmployeeId = 1,则查询应返回具有相同位置的所有员工。

Output: 
@EmployeeId = 1
1
2
3

员工 4 和 6 的位置 1、2、3 和 4。它与员工 1 的位置 1 和 2 不完全匹配,员工 5 的位置列表完全不同 (3、4)。

@EmployeeId = 4
4
6

员工 1、2 和 3 具有位置 1 和 2。它与员工 4 拥有的位置 1、2、3 和 4 不完全匹配,而员工 5 具有部分位置列表 (3、4)。只有员工 4 和 6 具有相同的位置列表(1、2、3、4)。

@EmployeeId = 5
5

员工 1、2 和 3 的位置 1 和 2。它与员工 5 的位置 3 和 4 不完全匹配,员工 4 和 6 的位置列表更大(1、2、3、4) .

我开始写一个查询,但很困惑,这是我所拥有的,当然是不正确的。

DECLARE @EmployeeId int = 1

Select ELA.EmployeeId, ELA.LocationId from EmployeeLocationAssn ELA
Where not exists 
(Select ELA.LocationId from EmployeeLocationAssn ELA2 where ELA2.EmployeeId = @EmployeeId
EXCEPT
Select ELA.LocationId from EmployeeLocationAssn ELA3 where ELA3.EmployeeId = ELA.EmployeeId)
and ELA.EmployeeId <> @EmployeeId;

【问题讨论】:

    标签: sql sql-server database tsql


    【解决方案1】:

    您可以使用string_agg(如果使用 SQL Server 2017+)来比较员工:

    declare @EmployeeId int = 1;
    
    with cte as (
        select E.EmployeeId
            , string_agg(E.LocationId,',') within group (order by LocationId asc) LocationGroup
        from EmployeeLocationAssn E
        group by E.EmployeeId
    )
    select EmployeeId
    from cte
    where LocationGroup = (select LocationGroup from cte where EmployeeId = @EmployeeId);
    

    或者for xml path如果使用较低版本:

    declare @EmployeeId int = 1;
    
    with cte as (
      select E.EmployeeId, 
        substring(
          (
            select ',' + convert(varchar(12),E1.LocationId) as [text()]
            from #EmployeeLocationAssn E1
            where E1.EmployeeId = E.EmployeeId
            order by E1.LocationId
            for xml path ('')
          ), 2, 1000) LocationGroup
      from #EmployeeLocationAssn E
      group by E.EmployeeId
    )
    select EmployeeId
    from cte
    where LocationGroup = (select LocationGroup from cte where EmployeeId = @EmployeeId);
    

    dbfiddle

    【讨论】:

    • 我想得到结果 1、2 和 3,因为它们完全匹配员工 id 1 的位置,即 locationids 1 和 2。EmployeeId 4、5 和 6 不应该出现,因为它们有更多比一场比赛。希望我能正确解释。
    • @SriReddy 好的,现在试试。
    • 对这些查询的性能方面的任何建议。我预计 1000x50=50000 条记录,未来可能会增长更多。
    • @SriReddy 他们可能不会表现得那么好 TBH...必须为整个表计算 LocationGroup 值。您可能会更快地找到 Stu 的解决方案。最好的办法是在查询分析器中尝试并查看百分比。虽然这取决于您使用的是string_agg 解决方案还是for xml 解决方案?
    • 是的,在粗略的测试中,Stu 的解决方案的执行速度是原来的两倍。 Bilals 解决方案的执行速度再次提高了一倍(一旦根据 Stus cmets 固定)。
    【解决方案2】:

    这是适用于您的条件的替代查询,检查位置是否与所选员工的位置匹配,不在所选员工未使用的位置中,并且位置数量是否匹配。

     declare @EmployeeId int=1
    
           ;with x as (
                select locationid, Count(*) over() Qty
                from EmployeeLocationAssn
                where employeeid=@EmployeeId group by LocationId
            )
            select distinct EmployeeId
            from x join EmployeeLocationAssn e on e.LocationId=x.LocationId
            where e.employeeid not in (
                select EmployeeId
                from EmployeeLocationAssn e2
                where LocationId not in (select locationId from x)
            )
            and x.qty=(select Count(*) from EmployeeLocationAssn e3 where e3.EmployeeId=e.EmployeeId)
    

    【讨论】:

    • 分号是一个声明 terminator 而不是 begininator :)
    • @DaleK 确实是 - 除非 CTE 需要它们,如果不是批处理中的第一个语句 - 否则 sqlserver 会抛出 Incorrect syntax near the keyword 'with'. If this statement is a common table expression, an xmlnamespaces clause or a change tracking context clause, the previous statement must be terminated with a semicolon.
    • 没错,习惯的力量,我猜这与老狗和新花样有关;)
    • 教新手养成好习惯很好。
    • 无论经验如何,对每个人都有好处 - 没有人永远不会不学习 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-12
    • 2020-01-04
    • 2021-10-24
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多