スーパーセットのみを選択


10

次のコマンドで作成できる2つのテーブル(非クラスター化インデックスと共に)があります。

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);

技術的にはテーブルが少し異なり、他のいくつかのテーブルに参加していますが、これは私の状況に適したプロキシです。

  • GroupKeys別のサブセットではないものをすべて選択したいGroupKey
  • 特定のスーパーセットについて、GroupScoreすべてのサブセット(それ自体を含む)の最大値を取得したいと思います。
  • a GroupKeyRecordKeys別のとまったく同じものが含まれている場合GroupKey(s)、そのうちの1つだけGroupKeysが取得されます(どちらを使用してもかまいません)。
  • 別のものとGroupKeyまったく同じであるものはすべて同じになります。RecordKeysGroupKey(s)GroupScore
  • 非関連GroupKeysも同じスコアを持つことができます。

以下は私が求めていることを説明するための例です:

              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

出力を次のようにしたいと思います。

GroupKey    RecordCount    GroupScore
-------------------------------------
  1              3             9.8
  192            4             9.8

GroupTable75M行の周りにあり、RecordTable周り115M行を持っています。ただし、結合とWHERE述語の後、特定の日に約2万行になる傾向があります。

この質問が些細なものである場合はお詫び申し上げますが、何らかの理由で私は本当にそれに苦労しています。

回答:


7

出力を次のようにしたいと思います。

 GroupKey    RecordCount    GroupScore
 -------------------------------------
   1              3             9.8
   192            4             7.1

相関サブクエリの使用は、必要な出力を取得する1つの方法です。

  • GroupKeyに別のGroupKeyとまったく同じRecordKeyが含まれている場合、それらのGroupKeyの1つだけが取得されます(どちらでもかまいません)。

一致した場合、GroupKeyが最も低いGroupを返しますが、重要ではないと言うのは任意です。

テストデータ:

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

クエリ:

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

SELECTのサブクエリは、GroupScoreこの( 'g1')グループのサブセットであるグループのみから最高のものを取得します。これRecordKeyは、「g1」セットと各「g2」セットの「」のUNIONをカウントすることでこれを実現します。UNIONが「g1」セットよりも大きい場合、「g1」セットにRecordKey対応するものRecordKeyがない「g2」セットに少なくとも1つ存在する必要があるため、「g2」セットはサブセットではなく、この行。

WHERE句では、フィルタリングについて2つのケースを検討する必要があります。どちらの場合でも、「g1」セットは、すべての「g1」RecordKeyも「g3」セットに存在する場合にのみフィルタリングされます。このチェックは、ユニオンを再度カウントすることによって行われます(SELECT句のとおり)。

2つのケースは、次のとおりです:① 'g1'セットRecordKeyのs は少ない(g3.RecordCount>g1.RecordCount;この場合、フィルターをかけます)、および② 'g1'セットは 'g3'セットと同一です(g3.RecordCount=g1.RecordCount;この場合、より低いGroupKey

出力:

/*
|GroupKey|RecordCount|GroupScore|
|-------:|----------:|---------:|
|       1|          3|       9.8|
|     192|          4|       9.8|
*/

ここ dbfiddle


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.