Select 行基于匹配另一列标识符内所有行的列内容?

Select rows based on matching a column contents across all rows within an identifier in another column?

运行 SQL 服务器 14.0.2037.2 Windows 10 企业版 21H1

我试图 return 仅当该 ID 内所有行的另一列条目在第二个 table 中与类似列的条目匹配时,再次在特定 ID 内。 例如,

create table #F(patentid VARCHAR(8), subclass VARCHAR(3));

insert into #F values ('l','x');
insert into #F values ('l','y');
insert into #F values ('l','z');

insert into #F values ('m','x');

insert into #F values ('n','z');


create table #P(patentid VARCHAR(8), subclass VARCHAR(3));


insert into #P values ('b','x');

insert into #P values ('c','w');
insert into #P values ('c','x');
insert into #P values ('c','y');
insert into #P values ('c','z');

insert into #P values ('d','x');
insert into #P values ('d','y');
insert into #P values ('d','z');

insert into #P values ('e','x');
insert into #P values ('e','y');
insert into #P values ('e','z');

我正在尝试编写一个查询,该查询将 return 对于 #F 中的每个 patentid,#P 中子类条目完全匹配的所有 patentID。 #F 中的“l”与#P 中的“d”和“e”相匹配[匹配的子类是 'x'、'y' 和 'z'] 以及 #F 中与 #P 中的“b”匹配的“m”[匹配的子类是“x”]

输出应该是:

l, d
l, e
m, b

代码需要高效,因为#F 和#P 都包含数百万行。我已经尝试过 Union,但是它适用于整组行并且不允许通过子集进行匹配(即在 patentid 中)

非常感谢任何帮助。

这对你来说足够有效吗?

select f.patentId, p.patentid 
from (
    select patentId, STRING_AGG(subclass,'') WITHIN GROUP (ORDER BY subclass ASC) as class 
    from #F 
    group by patentId
) f
inner join (
    select patentId, STRING_AGG(subclass,'') WITHIN GROUP (ORDER BY subclass ASC) as class 
    from #P 
    group by patentId
) p on f.class = p.class

这是一个 Relational Division Without Remainder 的例子,有多个除数

换句话说,您想将 #F 除以 #P,并且只取没有余数的结果。

解决办法有很多,这里就一个

  • 将 table 按 patentid 划分并计算窗口计数
  • 通过 subclass 将一个 table 左连接到另一个 subclass,过滤完全匹配的计数
  • 按 ID 对分组
  • 过滤掉所有 f.subclass 不具有匹配 p.subclass 的任何内容,我们使用 HAVING COUNT(*) = COUNT(p.subclass) 执行此操作,因为 COUNT(p.subclass) 仅计算非空值。
SELECT
  f.patentid, p.patentid
FROM (
    SELECT *,
      cnt = COUNT(*) OVER (PARTITION BY f.patentid)
    FROM #F f
) f
LEFT JOIN (
    SELECT *,
      cnt = COUNT(*) OVER (PARTITION BY p.patentid)
    FROM #P p
) p ON p.cnt = f.cnt AND p.subclass = f.subclass
GROUP BY
  f.patentid, p.patentid
HAVING COUNT(*) = COUNT(p.subclass);

db<>fiddle