我有用户,职位和许可证。

关系是:


用户可能有很多许可证
职位可能需要很多执照


因此,我可以轻松获得每个职位的许可证要求以及每个用户的有效许可证。

但是我想知道匹配这两组的最佳方法是什么?随着逻辑的发展,用户至少需要某个职位所需的那些许可证。可能还有更多,但其余的都不相关。

我想获得用户和合格职位的结果。

PersonID PositionID
1        1          -> user 1 is eligible to work on position 1
1        2          -> user 1 is eligible to work on position 2
2        1          -> user 2 is eligible to work on position 1
3        2          -> user 3 is eligible to work on position 2
4        ...


如您所见,我需要为所有用户提供一个结果,而不是每个呼叫一个,这会使事情变得容易得多。



这里实际上有5个表:

create table Person ( PersonID, ...)
create table Position (PositionID, ...)
create table License (LicenseID, ...)


和关系

create table PersonLicense (PersonID, LicenseID, ...)
create table PositionLicense (PositionID, LicenseID, ...)


因此,基本上,我需要找到某个人被许可从事工作的职位。当然,这里还有一个更复杂的问题,因为还有其他因素,但是主要目标是相同的:

如何将一个关系表的多个记录与另一个关系表的多个记录进行匹配。也可以将其描述为每组记录的inner join,而不是通常在TSQL中完成的每条记录。

我在考虑TSQL语言构造:


行集,但我从未使用过它们,也不知道如何使用它们
intersect语句虽然可能只适用于整个集合而不适用于组

最佳答案

最终解决方案(以供将来参考)

同时,当其他开发人员回答我的问题时,这是我想到的,并使用了CTE和分区,这些当然可以在SQL Server 2008 R2上使用。我以前从未使用过结果分区,所以我不得不学习一些新知识(加在一起)。这是代码:

with CTEPositionLicense as (
    select
        PositionID,
        LicenseID,
        checksum_agg(LicenseID) over (partition by PositionID) as RequiredHash
    from PositionLicense
)
select per.PersonID, pos.PositionID
from CTEPositionLicense pos
    join PersonLicense per
    on (per.LicenseID = pos.LicenseID)
group by pos.PositionID, pos.RequiredHash, per.PersonID
having pos.RequiredHash = checksum_agg(per.LicenseID)
order by per.PersonID, pos.PositionID;


因此,我对以下三种技术进行了比较:


Cross join(由Andriy M撰写)
Table variable(由Petar Ivanov撰写)
校验和-这是这里(由Robert Koritnik,我)


我的人已经按人和位置订购了结果,所以我也将相同的结果添加到其他两个人中以使返回的结果相同。

产生的估计执行计划


校验和:7%
表变量:2%(表创建)+ 9%(执行)= 11%
交叉加入:82%


我还将Table变量版本更改为CTE版本(而不是使用CTE代替表变量),并在最后删除了order by并比较了其估计的执行计划。仅供参考,CTE版本为43%,原始版本为53%(10%+ 43%)。

10-06 12:39
查看更多