2017-04-04 5 views
0

Kontext:Erstellen Sie Gruppen in einer Tabelle basierend auf Gruppenproportionen aus einer anderen Tabelle

Ich habe zwei Tabellen. TABELLE A hat Daten mit beispielsweise Format (mit 12 Gruppen AL bestellt, A = höchste, L = niedrigste):

ID | BAND 
---- | ---- 
1 | A  
2 | B 
3 | A 
4 | C 
5 | D 
6 | F 
7 | D 
8 | H 
... 

TABELLE B Daten mit beispielsweise Format hat:

ID | SCORE 
---- | ---- 
1 | 0.12  
2 | 0.37 
3 | 0.21 
4 | 0.55 
5 | 0.01 
6 | 0.90 
7 | 0.10 
8 | 0.71  
... 

I haben berechnet, die proportionalen Größen von jeder Gruppe in der Tabelle A unter Verwendung von:

CREATE TABLE table_a_group_pct AS 
SELECT band 
, count(*) * 100.0/sum(count(*)) over() AS pct 
FROM table_a 
GROUP BY band; 

Mit Ausgang:

BAND | PCT 
---- | ---- 
A | 12 
B | 15 
C | 11 
D | 9 
E | 10 
F | 8 
G | 11 
H | 10 
I | 6 
J | 4 
K | 3 
L | 1 

Ich wünsche 12 geordnet (von score) Gruppen für Tabelle B mit den gleichen proportionalen Größen wie die Gruppen in Tabelle A erstellen

Z.B. 12% der Zeilen in TABELLE A haben group = A, dann die obersten 12% rows (basierend auf der Punktzahl) würde group = A und so weiter gegeben ...

Ich denke, ich kann das Problem lösen, indem ich die NTILE(100) Funktion, um die% -Position jeder Punktzahl zu finden und dann eine CASE WHEN zu verwenden, um manuelle Gruppen basierend auf dem kumulativen% jeder Gruppe in Tabelle A zu erstellen (dh wenn Band A die oberen 12% der IDs hat, dann finde ich das 88. Perzentil in TABELLE B und zu tun:

CASE WHEN score_pct > 88 then 'A' 
    WHEN score_pct BETWEEN 88 and 73 then 'B' ... 
END AS group` 

aber ich versuche es zu verstehen, wenn smarter Weg, dieses Problem zu bewältigen

Weitere informatio. N: TABELLE A & TABELLE B haben nicht die gleiche Größe und nicht die exakt gleichen IDs, ich versuche nur ähnlich proportionierte Gruppen zu erstellen.

Meine erwartete Ausgabe ist so etwas wie folgt aus:

ID | SCORE | BAND 
---- | ---- | ---- 
1 | 0.12 | K/11 
2 | 0.37 | G/7 
3 | 0.21 | H/8 
4 | 0.55 | E/5 
5 | 0.01 | L/12 
6 | 0.90 | A/1 
7 | 0.10 | K/11 
8 | 0.71 | B/2 

[meine Frage Edited hinzufügen Klarheit]

+0

Können Sie die erwartete Ausgabe einschließen? –

+0

Nein ... editiere deine Frage, wir können deine Gedanken nicht lesen –

+0

Irgendwie macht die Frage für mich keinen Sinn. Sie beginnen damit, dass es * 12 * geordnete Bandings gibt und zeigen dann Tabellen mit * 8 * Zeilen. Vielleicht sollten Sie eine weitere * Frage stellen, die eine vereinfachte Version Ihres Problems und eine klarere Erklärung darstellt. Was ist zum Beispiel die "proportionale Größe von Tabelle A"? –

Antwort

1

Dies wird durch Verwendung der CUME_DIST analytische Funktion zusammen mit einigen funkigen Beitritt (in prä- erreicht werden kann 12c) wie folgt:

(NB Ich habe die Daten in Tabelle_a so geändert, dass sie die ersten 8 Noten enthält; dies stimmt nicht mit Ihren Beispieldaten überein, also seien Sie nicht überrascht, wenn meine Ausgabe nicht zu Ihrer passt .)

WITH table_a AS (SELECT 1 ID, 'A' band FROM dual UNION ALL 
       SELECT 2 ID, 'B' band FROM dual UNION ALL 
       SELECT 3 ID, 'A' band FROM dual UNION ALL 
       SELECT 4 ID, 'C' band FROM dual UNION ALL 
       SELECT 5 ID, 'D' band FROM dual UNION ALL 
       SELECT 6 ID, 'E' band FROM dual UNION ALL 
       SELECT 7 ID, 'D' band FROM dual UNION ALL 
       SELECT 8 ID, 'F' band FROM dual), 
    table_b AS (SELECT 1 ID, 0.12 score FROM dual UNION ALL 
       SELECT 2 ID, 0.37 score FROM dual UNION ALL 
       SELECT 3 ID, 0.21 score FROM dual UNION ALL 
       SELECT 4 ID, 0.55 score FROM dual UNION ALL 
       SELECT 5 ID, 0.01 score FROM dual UNION ALL 
       SELECT 6 ID, 0.90 score FROM dual UNION ALL 
       SELECT 7 ID, 0.10 score FROM dual UNION ALL 
       SELECT 8 ID, 0.71 score FROM dual), 
-- end of data set-up, see the rest of the query below: 
     a_pc AS (SELECT DISTINCT band, 
         cume_dist() OVER (ORDER BY band) pc_cume_dist 
       FROM table_a), 
     b_pc AS (SELECT id, 
         score, 
         cume_dist() OVER (ORDER BY score DESC) pc_cume_dist 
       FROM table_b) 
SELECT b_pc.id, 
     b_pc.score, 
     b_pc.pc_cume_dist, 
     min(a_pc.band) band 
FROM b_pc 
     INNER JOIN a_pc ON (a_pc.band = CASE WHEN b_pc.pc_cume_dist <= a_pc.pc_cume_dist AND a_pc.band = 'A' THEN 'A' 
              WHEN b_pc.pc_cume_dist <= a_pc.pc_cume_dist AND a_pc.band = 'B' THEN 'B' 
              WHEN b_pc.pc_cume_dist <= a_pc.pc_cume_dist AND a_pc.band = 'C' THEN 'C' 
              WHEN b_pc.pc_cume_dist <= a_pc.pc_cume_dist AND a_pc.band = 'D' THEN 'D' 
              WHEN b_pc.pc_cume_dist <= a_pc.pc_cume_dist AND a_pc.band = 'E' THEN 'E' 
              WHEN b_pc.pc_cume_dist <= a_pc.pc_cume_dist AND a_pc.band = 'F' THEN 'F' 
             END) 
GROUP BY b_pc.id, b_pc.score, b_pc.pc_cume_dist 
ORDER BY b_pc.score DESC; 

     ID  SCORE PC_CUME_DIST BAND 
---------- ---------- ------------ ---- 
     6  0.9  0.125 A 
     8  0.71   0.25 A 
     4  0.55  0.375 B 
     2  0.37   0.5 C 
     3  0.21  0.625 D 
     1  0.12   0.75 D 
     7  0.1  0.875 E 
     5  0.01   1 F 

Oder in 12c Sie die LATERAL verwenden kann mitmachen, etwa so:

WITH table_a AS (SELECT 1 ID, 'A' band FROM dual UNION ALL 
       SELECT 2 ID, 'B' band FROM dual UNION ALL 
       SELECT 3 ID, 'A' band FROM dual UNION ALL 
       SELECT 4 ID, 'C' band FROM dual UNION ALL 
       SELECT 5 ID, 'D' band FROM dual UNION ALL 
       SELECT 6 ID, 'E' band FROM dual UNION ALL 
       SELECT 7 ID, 'D' band FROM dual UNION ALL 
       SELECT 8 ID, 'F' band FROM dual), 
    table_b AS (SELECT 1 ID, 0.12 score FROM dual UNION ALL 
       SELECT 2 ID, 0.37 score FROM dual UNION ALL 
       SELECT 3 ID, 0.21 score FROM dual UNION ALL 
       SELECT 4 ID, 0.55 score FROM dual UNION ALL 
       SELECT 5 ID, 0.01 score FROM dual UNION ALL 
       SELECT 6 ID, 0.90 score FROM dual UNION ALL 
       SELECT 7 ID, 0.10 score FROM dual UNION ALL 
       SELECT 8 ID, 0.71 score FROM dual), 
     a_pc AS (SELECT DISTINCT band, 
         cume_dist() OVER (ORDER BY band) pc_cume_dist 
       FROM table_a), 
     b_pc AS (SELECT id, 
         score, 
         cume_dist() OVER (ORDER BY score DESC) pc_cume_dist 
       FROM table_b) 
SELECT b_pc.id, 
     b_pc.score, 
     b_pc.pc_cume_dist, 
     a_pc2.band 
FROM b_pc, 
     lateral (SELECT MIN(band) band 
       FROM a_pc 
       WHERE a_pc.pc_cume_dist >= b_pc.pc_cume_dist) a_pc2 
order by b_pc.score desc 

     ID  SCORE PC_CUME_DIST BAND 
---------- ---------- ------------ ---- 
     6  0.9  0.125 A 
     8  0.71   0.25 A 
     4  0.55  0.375 B 
     2  0.37   0.5 C 
     3  0.21  0.625 D 
     1  0.12   0.75 D 
     7  0.1  0.875 E 
     5  0.01   1 F 

Hier ist ein Beispiel dafür LiveSQL (which is at version 12.2) auf Oracle ausgeführt wird.

+0

Die cume_dist Funktion funktioniert dank! – tfcoe

Verwandte Themen