只选择超集

bas*_*n22 10 sql-server t-sql sql-server-2014

我有两个可以使用以下命令创建的表(以及一个非聚集索引):

CREATE TABLE GroupTable
(
  GroupKey int NOT NULL PRIMARY KEY, 
  RecordCount int NOT NULL,
  GroupScore float NOT NULL
);

CREATE TABLE RecordTable
(
  RecordKey varchar(10) NOT NULL, 
  GroupKey int NOT NULL,
  PRIMARY KEY(RecordKey, GroupKey)
);

CREATE UNIQUE INDEX ixGroupRecord ON RecordTable(GroupKey, RecordKey);
Run Code Online (Sandbox Code Playgroud)

虽然从技术上讲,我的表略有不同,而且我正在加入其他一些表,但这是适合我的情况的代理。

  • 我想选择所有GroupKeys不是另一个GroupKey.
  • 对于给定的超集,我想获取其GroupScore所有子集(包括其自身)的最大值。
  • 在 aGroupKey包含与RecordKeysanother完全相同的实例中GroupKey(s),则只GroupKeys抓取其中一个(哪个无关紧要)。
  • 任何与另一个GroupKey完全相同的也将具有相同的.RecordKeysGroupKey(s)GroupScore
  • 不相关的GroupKeys也可以有相同的分数。

下面是一个例子来说明我在问什么:

CREATE TABLE GroupTable
(
  GroupKey int NOT NULL PRIMARY KEY, 
  RecordCount int NOT NULL,
  GroupScore float NOT NULL
);

CREATE TABLE RecordTable
(
  RecordKey varchar(10) NOT NULL, 
  GroupKey int NOT NULL,
  PRIMARY KEY(RecordKey, GroupKey)
);

CREATE UNIQUE INDEX ixGroupRecord ON RecordTable(GroupKey, RecordKey);
Run Code Online (Sandbox Code Playgroud)

我希望输出如下:

              GroupTable                          RecordTable

GroupKey    RecordCount   GroupScore         RecordKey    GroupKey
------------------------------------         ---------------------
  1              3            6.2                A          1
  29             2            9.8                A          29
  95             3            6.2                A          95
  192            4            7.1                A          192
                                                 B          1
                                                 B          29
                                                 B          95
                                                 B          192
                                                 C          1
                                                 C          95
                                                 D          192
                                                 E          192
Run Code Online (Sandbox Code Playgroud)

GroupTable大约有 75M 行,RecordTable大约有 115M 行;然而,在连接和WHERE谓词之后,在给定的一天往往有大约 20k 行。

如果这个问题微不足道,我深表歉意,但出于某种原因,我真的很挣扎。

Jac*_*las 7

我希望输出如下:

 GroupKey    RecordCount    GroupScore
 -------------------------------------
   1              3             9.8
   192            4             7.1
Run Code Online (Sandbox Code Playgroud)

使用相关子查询是获得所需输出的一种方法。

  • 在 GroupKey 包含与另一个 GroupKey 完全相同的 RecordKey 的情况下,则仅抓取这些 GroupKey 中的一个(与哪个无关)。

当匹配时,我将返回具有最低 GroupKey 的组,但这是任意的,因为您说这无关紧要。

测试数据:

INSERT INTO RecordTable(RecordKey,GroupKey)
VALUES ('A',1)
     , ('A',29)
     , ('A',95)
     , ('A',192)
     , ('B',1)
     , ('B',29)
     , ('B',95)
     , ('B',192)
     , ('C',1)
     , ('C',95)
     , ('D',192)
     , ('E',192);

INSERT INTO GroupTable(GroupKey,RecordCount,GroupScore)
VALUES (1,3,6.2)     -- ABC
     , (29,2,9.8)    -- AB
     , (95,3,6.2)    -- ABC
     , (192,4,7.1);  -- ABDE
GO
Run Code Online (Sandbox Code Playgroud)

询问:

SELECT GroupKey
     , RecordCount
     , GroupScore = ( SELECT max(GroupScore)
                      FROM GroupTable g2 
                      WHERE ( SELECT count(*)
                              FROM ( SELECT RecordKey
                                     FROM RecordTable
                                     WHERE GroupKey=g1.GroupKey
                                     UNION
                                     SELECT RecordKey
                                     FROM RecordTable
                                     WHERE GroupKey=g2.GroupKey ) z
                            )=g1.RecordCount )
FROM GroupTable g1
WHERE NOT EXISTS ( SELECT *
                   FROM GroupTable g3
                   WHERE ( SELECT count(*)
                           FROM ( SELECT RecordKey
                                  FROM RecordTable 
                                  WHERE GroupKey=g1.GroupKey 
                                  UNION
                                  SELECT RecordKey 
                                  FROM RecordTable 
                                  WHERE GroupKey=g3.GroupKey ) z )=g3.RecordCount
                         AND ( g3.RecordCount>g1.RecordCount 
                               OR ( g3.RecordCount=g1.RecordCount 
                                    AND g3.GroupKey<g1.GroupKey ) ) );
GO
Run Code Online (Sandbox Code Playgroud)

SELECT 中的子查询GroupScore仅从作为此 ('g1') 组子集的那些组中获得最高值。它通过计算RecordKey'g1' 集和每个 'g2' 集的's的 UNION 来实现这一点。如果 UNION 大于 'g1' 集,则RecordKey'g2' 集中必须至少有一个没有对应RecordKey于 'g1' 集的,因此 'g2' 集不是子集,不应考虑这一行。

在 WHERE 子句中,过滤需要考虑两种情况。在任何一种情况下,只有在所有 'g1'RecordKey都存在于 'g3' 集中时,才过滤 'g1 ' 集;这个检查是通过再次计算联合来实现的(根据 SELECT 子句)。

这两种情况是: ? 'g1' 集合的RecordKeys ( g3.RecordCount>g1.RecordCount; 在这种情况下我们过滤),并且 ? 'g1' 集与 'g3' 集相同(g3.RecordCount=g1.RecordCount在这种情况下,我们任意选择具有较低 的集GroupKey

输出:

/*
|GroupKey|RecordCount|GroupScore|
|-------:|----------:|---------:|
|       1|          3|       9.8|
|     192|          4|       9.8|
*/
Run Code Online (Sandbox Code Playgroud)

dbfiddle在这里