Yalnızca Seçili Üst Gruplar


10

Aşağıdaki komutlarla oluşturulabilir iki tablo (kümelenmemiş bir dizin ile birlikte) var:

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

Teknik olarak tablolarım biraz farklı olsa da ve birkaç masaya katılıyorum, bu durumum için uygun bir proxy.

  • Başka birinin GroupKeysalt kümesi olmayan her şeyi seçmek istiyorum GroupKey.
  • Belirli bir süper GroupScoreküme için, tüm alt kümelerinin (kendisi dahil) maksimumunu almak istiyorum .
  • A'nın bir diğeriyle GroupKeyaynı kesinliği içermesi durumunda , bunlardan sadece biri yakalanır (hangisinin önemli olduğu önemli değildir).RecordKeysGroupKey(s)GroupKeys
  • Bir başkasıyla GroupKeyaynı kesinliğe sahip olanlar da aynı olacaktır .RecordKeysGroupKey(s)GroupScore
  • İlişkili olmayanlar GroupKeysda aynı puana sahip olabilir.

Aşağıdakileri sorduğumu gösteren bir örnek:

              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

Çıktı aşağıdaki gibi istiyorum:

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

GroupTableyaklaşık 75M sıraya RecordTablesahiptir ve yaklaşık 115M sıraya sahiptir; ancak, birleşimler ve WHEREyüklemden sonra, belirli bir günde yaklaşık 20 bin satır olma eğilimindedir.

Bu sorunun önemsiz olup olmadığı için özür dilerim, ama nedense gerçekten bununla mücadele ediyorum.

Yanıtlar:


7

Çıktı aşağıdaki gibi istiyorum:

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

İlişkili alt sorguları kullanmak, istediğiniz çıktıyı almanın bir yoludur.

  • Bir GroupKey, başka bir GroupKey ile aynı RecordKey'leri içerdiğinde, bu GroupKey'lerden yalnızca biri yakalanır (hangisinin önemli olduğu).

Bir maç olduğunda en düşük GroupKey grubuna geri dönüyorum, ama bunun önemli olmadığını söylediğiniz gibi keyfi.

test verisi:

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

sorgu:

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 içindeki alt sorgu GroupScore, yalnızca bu ('g1') grubunun alt kümeleri olan gruplardan en yüksek olanı alır. Bunu RecordKey'g1' seti ve her 'g2' seti için BİRLİĞİ sayarak başarır . BİRLİĞİ 'g1' kümesinden daha büyükse, ' RecordKeyg2' kümesinde RecordKey'g1' kümesine karşılık gelmeden en az bir tane olmalıdır , bu nedenle 'g2' kümesi bir alt küme değildir ve dikkate alınmamalıdır. bu satır.

WHERE yan tümcesinde, filtreleme için dikkate alınması gereken iki durum vardır. Her iki durumda da, 'g1' seti yalnızca RecordKey'g3' setinin tamamı 'g3' setinde de mevcutsa filtrelenir ; ve bu kontrol birleşmeyi tekrar sayarak gerçekleştirilir (SELECT yantümcesine göre).

İki durum şunlardır: ① 'g1' setinde daha az RecordKeys vardır ( g3.RecordCount>g1.RecordCount; bu durumda filtreliyoruz) ve ② 'g1' seti 'g3' setiyle aynıdır ( g3.RecordCount=g1.RecordCount; bu durumda seti keyfi olarak düşük GroupKey)

çıktı:

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

dbfiddle burada


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.