2017-06-28 1 views
1

Ich habe eine Tabelle mit drei Spalten mit einer ID, eine therapeutische Klasse und dann einen generischen Namen. Eine therapeutische Klasse kann mehreren generischen Namen zugeordnet werden.SQL eindeutige Kombinationen

ID  therapeutic_class  generic_name 
1   YG4     insulin 
1   CJ6     maleate 
1   MG9     glargine 
2   C4C     diaoxy 
2   KR3     supplies 
3   YG4     insuilin 
3   CJ6     maleate 
3   MG9     glargine 

Ich brauche zuerst an den einzelnen Kombinationen von therapeutischer Klasse und Gattungsnamen zu suchen und dann zählen will, wie viele Patienten die gleiche Kombination hat. Ich möchte, dass meine Ausgabe drei Spalten haben: zum einen die Combo der Gattungsnamen sind, die Kombination aus therapeutischen Klassen und die Zählung der Anzahl der Patienten mit der Kombination wie folgt aus:

Count   Combination_generic     combination_therapeutic 
2    insulin, maleate, glargine     YG4, CJ6, MG9 
1    supplies, diaoxy       C4C, KR3 
+0

Sie sind für 'listagg suchen()' –

+0

[Nicht Beispieldaten als Screenshots post] (http://meta.stackoverflow.com/questions/ 285551/why-may-ich-nicht-upload-images-of-code-auf-so-wenn-eine-frage/285557 # 285557) Benutze formatierten Text - wie du es am Anfang getan hast. –

+0

Das Datenmodell ist nicht ganz richtig. Sie können separate Tabellen für therapeutische Klassen und für generische Namen haben (wenn Sie das nicht tun, sollten Sie), aber ein weiteres Stück fehlt. Vermutlich kann nicht jeder generische Name mit jeder therapeutischen Klasse assoziiert werden; Nur einige Paare sind gültig, während andere ungültig sind. Dies sollte in einer separaten Viele-zu-Viele-Zuordnungstabelle erfolgen, wobei jedem gültigen Paar eine eindeutige Kennung zugewiesen wird. Dann sollte Ihr Tisch mit Patienten und Paaren (therapeutische Klasse, generischer Name) stattdessen Patienten und eindeutige IDs solcher gültiger Paare haben. Dies würde auch die Abfrage vereinfachen. – mathguy

Antwort

0

Sie suchen listagg() suchen und dann eine weitere Aggregation. Ich denke:

select therapeutics, generics, count(*) 
from (select id, listagg(therapeutic_class, ', ') within group (order by therapeutic_class) as therapeutics, 
      listagg(generic_name, ', ') within group (order by generic_name) as generics 
     from t 
     group by id 
    ) t 
group by therapeutics, generics; 
+0

Dies kann fehlschlagen, wenn zwei verschiedene therapeutische Klassen auf dieselben zwei generischen Namen abgebildet werden können. Zum Beispiel können sowohl A als auch B generische Namen x und y haben. Dann werden mit den ORDER BY-Klauseln, wie geschrieben, zwei Patienten mit den Paaren (A, x), (B, y) und jeweils (A, y), (B, x) in die gleiche Gruppe in der Gruppe gesetzt Durch Therapeutika, Generika. – mathguy

+0

Auch die OP-Ausgabe scheint die generischen Namen in der Reihenfolge der therapeutischen Klassen in den durch Komma getrennten Strings angeordnet zu haben. Das wird mit den unabhängigen ORDER BY-Kriterien nicht funktionieren. – mathguy

1

Eine Möglichkeit, Patienten durch die Sätze von Paaren übereinstimmen (therapeutic_class, generic_name) ist es, die durch Kommata getrennte Strings in der gewünschten Ausgabe und zur Gruppe von ihnen und zählen zu erstellen. Um dies richtig zu machen, müssen Sie die Paare identifizieren. Siehe meinen Kommentar unter der ursprünglichen Frage und meine Kommentare zu Gordons Antwort, um einige der Probleme zu verstehen.

Ich mache diese Identifizierung in einigen Vorarbeiten in der Lösung unten. Wie ich in meinem Kommentar erwähnt habe, wäre es besser, wenn die Paare und eindeutigen IDs bereits in Ihrem Datenmodell vorhanden wären; Ich erstelle sie im laufenden Betrieb.

Wichtiger Hinweis: Dies setzt voraus, dass die durch Kommas getrennten Listen nicht zu lang werden. Wenn Sie 4000 Zeichen (oder ca. 32000 Zeichen in Oracle 12, mit bestimmten Optionen eingeschaltet), können Sie die Zeichenfolgen in CLOBs aggregieren, aber Sie können nicht GROUP BY CLOBs (in der Regel nicht nur in diesem Fall), also dies Ansatz wird fehlschlagen. Ein robusterer Ansatz besteht darin, die Paare von Paaren zu vergleichen, nicht irgendeine Ansammlung von ihnen. Die Lösung ist komplizierter, ich werde es nur behandeln, wenn es für Ihr Problem benötigt wird.

with 
     -- Begin simulated data (not part of the solution) 
     test_data (id, therapeutic_class, generic_name) as (
      select 1, 'GY6', 'insulin' from dual union all 
      select 1, 'MH4', 'maleate' from dual union all 
      select 1, 'KJ*', 'glargine' from dual union all 
      select 2, 'GY6', 'supplies' from dual union all 
      select 2, 'C4C', 'diaoxy' from dual union all 
      select 3, 'GY6', 'insulin' from dual union all 
      select 3, 'MH4', 'maleate' from dual union all 
      select 3, 'KJ*', 'glargine' from dual 
     ), 
     -- End of simulated data (for testing purposes only). 
     -- SQL query solution continues BELOW THIS LINE 
    valid_pairs (pair_id, therapeutic_class, generic_name) as (
     select rownum, therapeutic_class, generic_name 
     from (
       select distinct therapeutic_class, generic_name 
       from test_data 
      ) 
    ), 
    first_agg (id, tc_list, gn_list) as (
     select t.id, 
       listagg(p.therapeutic_class, ',') within group (order by p.pair_id), 
       listagg(p.generic_name  , ',') within group (order by p.pair_id) 
     from test_data t join valid_pairs p 
          on t.therapeutic_class = p.therapeutic_class 
          and t.generic_name  = p.generic_name 
     group by t.id 
    ) 
select count(*) as cnt, tc_list, gn_list 
from  first_agg 
group by tc_list, gn_list 
; 

Ausgang:

CNT TC_LIST   GN_LIST      
--- ------------------ ------------------------------ 
    1 GY6,C4C   supplies,diaoxy    
    2 GY6,KJ*,MH4  insulin,glargine,maleate  
Verwandte Themen