Nur Supersets auswählen

10

Ich habe zwei Tabellen (zusammen mit einem nicht gruppierten Index), die mit den folgenden Befehlen erstellt werden können:

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

Obwohl meine Tabellen technisch etwas anders sind und ich mich einigen anderen Tabellen anschließe, ist dies ein geeigneter Proxy für meine Situation.

  • Ich möchte alle auswählen GroupKeys, die keine Teilmengen einer anderen sind GroupKey.
  • Für eine bestimmte Obermenge möchte ich das Maximum GroupScorealler ihrer Teilmengen (einschließlich sich selbst) erfassen.
  • In dem Fall, in dem a GroupKeygenau dasselbe enthält RecordKeyswie ein anderes GroupKey(s), wird nur einer davon GroupKeyserfasst (es spielt keine Rolle, welcher).
  • Jeder GroupKey, der genau das gleiche RecordKeyswie ein anderer hat GroupKey(s), hat auch das gleiche GroupScore.
  • Nicht verwandte GroupKeyskönnen auch die gleiche Punktzahl haben.

Das Folgende ist ein Beispiel, um zu veranschaulichen, was ich frage:

              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

Ich möchte, dass die Ausgabe wie folgt lautet:

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

GroupTablehat ungefähr 75 Millionen Zeilen und RecordTablehat ungefähr 115 Millionen Zeilen; Nach den Verknüpfungen und dem WHEREPrädikat gibt es jedoch an einem bestimmten Tag in der Regel etwa 20.000 Zeilen.

Ich entschuldige mich, wenn diese Frage trivial ist, aber aus irgendeinem Grund habe ich wirklich Probleme damit.

basketballfan22
quelle

Antworten:

7

Ich möchte, dass die Ausgabe wie folgt lautet:

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

Die Verwendung korrelierter Unterabfragen ist eine Möglichkeit, die gewünschte Ausgabe zu erhalten.

  • In dem Fall, in dem ein GroupKey genau dieselben RecordKeys wie ein anderer GroupKey enthält, wird nur einer dieser GroupKeys erfasst (egal welcher).

Ich gebe die Gruppe mit dem niedrigsten GroupKey zurück, wenn es eine Übereinstimmung gibt, aber das ist willkürlich, wie Sie sagen, es spielt keine Rolle.

Testdaten:

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

Abfrage:

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

Die Unterabfrage in SELECT wird GroupScorenur von den Gruppen am höchsten bewertet , die Teilmengen dieser Gruppe ('g1') sind. Dies wird erreicht, indem die UNION der RecordKey's für die' g1'-Menge und jede 'g2'-Menge gezählt wird. Wenn die UNION größer als die 'g1'-Menge ist, muss mindestens eine RecordKeyin der' g2'-Menge vorhanden sein, ohne eine Entsprechung RecordKeyfür die 'g1'-Menge, daher ist die' g2'-Menge keine Teilmenge und sollte nicht berücksichtigt werden diese Reihe.

In der WHERE-Klausel sind zwei Fälle für die Filterung zu berücksichtigen. In beiden Fällen wird die 'g1'-Menge nur gefiltert, wenn alle' g1 ' RecordKeyauch in der' g3'-Menge vorhanden sind. und diese Prüfung wird erreicht, indem die Vereinigung erneut gezählt wird (gemäß der SELECT-Klausel).

Die beiden Fälle sind: ① die 'g1'-Menge hat weniger RecordKeys ( g3.RecordCount>g1.RecordCount; in diesem Fall filtern wir) und ② die' g1'-Menge ist identisch mit der 'g3'-Menge ( g3.RecordCount=g1.RecordCount; in diesem Fall wählen wir die Menge willkürlich mit der niedriger GroupKey)

Ausgabe:

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

dbfiddle hier

Jack sagt, versuchen Sie es mit topanswers.xyz
quelle
Lassen Sie uns diese Diskussion im Chat fortsetzen .
Jack sagt, versuchen Sie topanswers.xyz