Solo seleccione superconjuntos


10

Tengo dos tablas (junto con un índice no agrupado) que se pueden crear con los siguientes comandos:

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

Aunque técnicamente mis tablas son ligeramente diferentes y me estoy uniendo a algunas otras tablas, este es un proxy adecuado para mi situación.

  • Me gustaría seleccionar todos los GroupKeysque no son subconjuntos de otro GroupKey.
  • Para un superconjunto dado, me gustaría obtener el máximo GroupScorede todos sus subconjuntos (incluido él mismo).
  • En el caso en que un GroupKeycontiene exactamente lo mismo RecordKeysque otro GroupKey(s), entonces solo uno de ellos GroupKeyses agarrado (no importa cuál).
  • Cualquiera GroupKeyque tenga exactamente lo mismo RecordKeysque otro GroupKey(s)también tendrá lo mismo GroupScore.
  • No relacionado también GroupKeyspuede tener el mismo puntaje.

El siguiente es un ejemplo para ilustrar lo que estoy preguntando:

              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

Me gustaría que la salida sea la siguiente:

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

GroupTabletiene alrededor de RecordTable75 millones de filas y tiene alrededor de 115 millones de filas; sin embargo, después de las uniones y el WHEREpredicado, tiende a haber alrededor de 20k filas en un día determinado.

Pido disculpas si esta pregunta es trivial, pero por alguna razón realmente estoy luchando con ella.

Respuestas:


7

Me gustaría que la salida sea la siguiente:

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

El uso de subconsultas correlacionadas es una forma de obtener el resultado que desea.

  • En el caso de que una GroupKey contenga las mismas RecordKeys exactas que otra GroupKey (s), solo se captura una de esas GroupKeys (no importa cuál).

Devolveré el Grupo con la GroupKey más baja cuando haya una coincidencia, pero eso es arbitrario, ya que usted dice que no importa.

datos de prueba:

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

consulta:

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 subconsulta en SELECT obtiene el máximo GroupScorede solo aquellos grupos que son subconjuntos de este grupo ('g1'). Lo logra contando la UNIÓN de los RecordKey's para el conjunto' g1 'y cada conjunto' g2 '. Si la UNION es más grande que el conjunto 'g1', debe haber al menos uno RecordKeyen el conjunto 'g2' sin un correspondiente RecordKeypara el conjunto 'g1', por lo que el conjunto 'g2' no es un subconjunto y no debe considerarse para esta fila

En la cláusula WHERE, hay dos casos a considerar para el filtrado. En cualquier caso, el conjunto 'g1' solo se filtra si todos los 'g1' RecordKeytambién están presentes en el conjunto 'g3'; y esta verificación se logra contando nuevamente la unión (según la cláusula SELECT).

Los dos casos son: ① el conjunto 'g1' tiene menos RecordKeys ( g3.RecordCount>g1.RecordCount; en cuyo caso filtramos), y ② el conjunto 'g1' es idéntico al conjunto 'g3' ( g3.RecordCount=g1.RecordCount; en cuyo caso elegimos arbitrariamente el conjunto con el inferior GroupKey)

salida:

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

dbfiddle aquí


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.