Hanya Pilih Superset


10

Saya memiliki dua tabel (bersama dengan indeks nonclustered) yang dapat dibuat dengan perintah di bawah ini:

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

Walaupun secara teknis tabel saya sedikit berbeda dan saya bergabung di beberapa tabel lain, ini adalah proksi yang cocok untuk situasi saya.

  • Saya ingin memilih semua GroupKeysyang bukan himpunan bagian dari yang lain GroupKey.
  • Untuk superset yang diberikan, saya ingin meraih maksimum GroupScoresemua himpunan bagiannya (termasuk dirinya sendiri).
  • Dalam contoh ketika a GroupKeyberisi persis sama RecordKeysdengan yang lain GroupKey(s), maka hanya satu dari yang GroupKeysdiambil (tidak masalah yang mana).
  • Apa pun GroupKeyyang memiliki persis sama RecordKeysdengan yang lain GroupKey(s)juga akan memiliki yang sama GroupScore.
  • Tidak terkait GroupKeysdapat memiliki skor yang sama juga.

Berikut ini adalah contoh untuk menggambarkan apa yang saya tanyakan:

              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

Saya ingin hasilnya sebagai berikut:

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

GroupTablememiliki sekitar 75M baris, dan RecordTablememiliki sekitar 115M baris; Namun, setelah bergabung dan WHEREpredikat, cenderung ada sekitar 20 ribu baris pada hari tertentu.

Saya minta maaf jika pertanyaan ini sepele, tetapi untuk beberapa alasan saya benar-benar berjuang dengan itu.

Jawaban:


7

Saya ingin hasilnya sebagai berikut:

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

Menggunakan subqueries yang dikorelasikan adalah salah satu cara untuk mendapatkan output yang Anda inginkan.

  • Dalam contoh ketika sebuah GroupKey berisi RecordKeys yang sama persis dengan GroupKey yang lain, maka hanya satu dari GroupKeys yang diambil (tidak masalah yang mana).

Saya mengembalikan Grup dengan GroupKey terendah ketika ada kecocokan, tetapi itu sewenang-wenang seperti yang Anda katakan tidak masalah.

data uji:

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

pertanyaan:

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

Subquery dalam SELECT mendapatkan yang tertinggi GroupScoredari hanya grup yang merupakan himpunan bagian dari grup ('g1') ini. Ini mencapai ini dengan menghitung UNION dari RecordKey'untuk' set g1 'dan masing-masing set' g2 '. Jika UNION lebih besar dari set 'g1', harus ada setidaknya satu RecordKeydi set 'g2' tanpa yang sesuai RecordKeyuntuk set 'g1', jadi set 'g2' bukan subset dan tidak boleh dipertimbangkan untuk baris ini.

Dalam klausa WHERE, ada dua hal yang perlu dipertimbangkan untuk pemfilteran. Dalam kedua kasus tersebut, set 'g1' hanya difilter jika semua 'g1 RecordKeyjuga ada dalam set' g3 '; dan pemeriksaan ini dicapai dengan menghitung serikat lagi (sesuai klausa SELECT).

Dua kasus tersebut adalah: ① set 'g1' memiliki lebih sedikit RecordKeys ( g3.RecordCount>g1.RecordCount; dalam hal ini kita memfilter), dan ② set 'g1' identik dengan set 'g3' ( g3.RecordCount=g1.RecordCount; dalam hal ini kita secara sewenang-wenang memilih set dengan lebih rendah GroupKey)

keluaran:

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

Aku di sini


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.