Sélectionner uniquement les sur-ensembles

10

J'ai deux tables (avec un index non cluster) qui peuvent être créées avec les commandes ci-dessous:

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

Bien que techniquement mes tables soient légèrement différentes et que je me joigne à quelques autres tables, c'est un proxy approprié pour ma situation.

  • Je voudrais sélectionner tous ceux GroupKeysqui ne sont pas des sous-ensembles d'un autre GroupKey.
  • Pour un sur-ensemble donné, je voudrais saisir le maximum GroupScorede tous ses sous-ensembles (y compris lui-même).
  • Dans le cas où a GroupKeycontient exactement la même chose RecordKeysqu'un autre GroupKey(s), alors un seul d'entre eux GroupKeysest saisi (peu importe lequel).
  • Tout ce GroupKeyqui a le même exact RecordKeysqu'un autre GroupKey(s)aura également le même GroupScore.
  • Les personnes non apparentées GroupKeyspeuvent également avoir le même score.

Voici un exemple pour illustrer ce que je demande:

              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

J'aimerais que la sortie soit la suivante:

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

GroupTablea environ 75 millions de lignes et RecordTableenviron 115 millions de lignes; cependant, après les jointures et le WHEREprédicat, il y a généralement environ 20 000 lignes un jour donné.

Je m'excuse si cette question est banale, mais pour une raison quelconque, je suis vraiment en difficulté avec elle.

basketballfan22
la source

Réponses:

7

J'aimerais que la sortie soit la suivante:

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

L'utilisation de sous-requêtes corrélées est un moyen d'obtenir la sortie souhaitée.

  • Dans le cas où une GroupKey contient les mêmes RecordKeys exactes qu'une autre GroupKey (s), alors une seule de ces GroupKeys est récupérée (peu importe laquelle).

Je renvoie le groupe avec la plus faible GroupKey lorsqu'il y a une correspondance, mais c'est arbitraire car vous dites que cela n'a pas d'importance.

données de test:

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

requete:

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

La sous-requête dans SELECT obtient le plus haut GroupScoreuniquement des groupes qui sont des sous-ensembles de ce groupe ('g1'). Il y parvient en comptant l'UNION des RecordKey's pour l'ensemble' g1 'et chaque ensemble' g2 '. Si l'UNION est plus grand que l'ensemble 'g1', il doit y en avoir au moins un RecordKeydans l'ensemble 'g2' sans correspondant RecordKeypour l'ensemble 'g1', donc l'ensemble 'g2' n'est pas un sous-ensemble et ne doit pas être pris en compte pour cette ligne.

Dans la clause WHERE, il y a deux cas à considérer pour le filtrage. Dans les deux cas, l'ensemble «g1» n'est filtré que si tous les «g1» RecordKeysont également présents dans l'ensemble «g3»; et cette vérification est obtenue en comptant à nouveau l'union (conformément à la clause SELECT).

Les deux cas sont: ① l'ensemble 'g1' a moins de RecordKeys ( g3.RecordCount>g1.RecordCount; auquel cas nous filtrons), et ② l'ensemble 'g1' est identique à l'ensemble 'g3' ( g3.RecordCount=g1.RecordCount; auquel cas nous choisissons arbitrairement l'ensemble avec le inférieur GroupKey)

production:

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

dbfiddle ici

Jack dit d'essayer topanswers.xyz
la source
Continuons cette discussion dans le chat .
Jack dit d'essayer topanswers.xyz