2017-12-27 3 views
1

Wie erreicht man "Nur in" Zustand in Orakel?Wie erreicht man 'Only in' Zustand in Orakel?

Ich habe zwei Tabellen 'PlanPlanSet' und 'ExcludedPlans'. PlanPlanSet enthält Pläne und den Plan, der jedem Plan zugeordnet ist. Ich möchte alle Datensätze von PlanPlanSet abrufen, in denen NUR IN ExcludedPlans geplant ist.

PlanPlanSet Tisch

Plan1 - Planset1 
Plan2 - Planset2 
Plan3 - Planset3 
Plan4 - Planset1 
Plan5 - Planset5 

ExcludedPlans Tabelle

Plan1 
Plan2 

Hier Planset1 enthält Plan1 und plan4 und Planset2 enthält nur Plan2. Daher sollte Planset1 nicht ausgeschlossen werden und Planset2 sollte ausgeschlossen werden. wie

Etwas,

select pps.planset 
from PlanPlanSet pps 
where pps.planNumber only in (select ex.planNumber 
           from ExcludedPlan ex); 
+0

Bitte können Sie das Schema der Tabellen hinzufügen? – cdaiga

+0

Planset2 enthält Plan5, warum sollte es anders als Planset1 behandelt werden? – Mat

+0

@ Mat- Sorry Ich habe die Werte bearbeitet. Jetzt enthält PlanSet2 nur Plan2 – user1940878

Antwort

2

Sie wollen alles von PLANSETS, wo jeder Plan innerhalb dieses Plans in der Liste der ausgeschlossenen Pläne enthalten ist.

Wenn Sie über diese Beziehung nachdenken, müssen Sie die beiden Tabellen zusammenfügen und feststellen, wo die Anzahl der Pläne auf jeder Seite gleich ist. Das heißt, wir müssen zulassen, dass sie anders sind, was einen LINKEN ÄUSSEREN VERBINDUNG bedeutet. Diese

select p.planset 
    from plansets p 
    left outer join excludedplans e 
    on p.plan = e.plan 
group by p.planset 
having count(p.plan) = count(e.plan) 

davon ausgehen, dass PLANSETS ist einzigartig auf PLANSET und PLAN und dass EXCLUDEDPLANS ist einzigartig auf PLAN. Wenn diese Annahme falsch ist, dann müssen Sie count(distinct ...

Wenn Sie alle Daten von PLANSETS wollen, dann kann die Logik in eine analytische Funktion

select * 
    from (select p.* 
       , count(p.plan) over (partition by p.planset) as planset_ct 
       , count(e.plan) over (partition by p.planset) as excluded_ct 
      from plansets p 
      left outer join excludedplans e 
      on p.plan = e.plan 
       ) 
where planset_ct = excluded_ct 
+0

Ich möchte alles von PLANSETS, wo jeder Plan in diesem Planset in der Liste der ausgeschlossenen Pläne enthalten ist. Ich soll nur solche Plansets finden, von denen alle Pläne in der ExcludedPlans-Tabelle vorhanden sind – user1940878

+0

Also müssen wir nur das '<>' in ein '=' dann ändern (was ich getan habe.) Ihre Beispielabfrage fragt nur nach dem Planset. Wollen Sie eigentlich alles? – Ben

+0

@ ben- Ich will nur die Ich habe versucht, <> mit = zu ändern, es funktioniert gut !! Thanksss !! Übrigens ist es möglich, diese Abfrage in eine Eclipse-Link-Abfrage zu konvertieren? – user1940878

2

Dies soll nur solche plansets von denen alle Pläne in ExcludedPlans Tabelle zu finden sind. Falls alle Zeilen für solche Plansets gewünscht sind, lassen Sie das distinct in der ersten Zeile aus und fügen Sie alle benötigten Spalten hinzu.

Select distinct planset 
From PlanPlanSet ps1 
Where 
exists 
(
    Select selected.planset 
    From 
    (
    Select ps2.planset, count(*) ct, sum(decode(ep2.plan, null, 0, 1)) present 
    From PlanPlanSet ps2 
    Left join ExcludedPlans ep2 on ep2.plan = ps2.plan 
    Group by ps2.planset 
) selected 
    Where selected.ct = selected.present and ps1.planset = selected.planset 
) 

Wenn im Gegenteil nur solche plansets von denen nicht alle Pläne in ExcludedPlans Tabelle vorhanden sind, sollte gewählt werden, dann die Unterabfrage ändern WHERE-Bedingung < selected.all> selected.present

+0

Hallo, Ihre äußere Inline-Ansicht hatte zwei WHERE-Klauseln, was die Ausführung verhinderte. Ich habe das geändert. Ich habe auch den Namen des Spaltenausdrucks 'count (*)' von 'all' in' ct' geändert. Dies liegt daran, dass 'all' ein reserviertes Wort ist, das Sie nicht als Namen verwenden können. Ich hoffe, es macht dir nichts aus. Sie können etwas wie [dbfiddle] (http://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=deb753011f14a0b2bec8a5c5ec13679a) verwenden, um vor dem Posten (oder danach!) Zu sehen, ob Ihr Code funktioniert oder nicht. Ihr Code [gibt nun das korrekte Ergebnis zurück] (http://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=be06852d3dbf406897c0e82a49521a17). – Ben

+0

@Ben macht mir überhaupt nichts aus! Danke für den Fiddle-Link, ich werde es überprüfen - in der Vergangenheit habe ich sqlfiddle benutzt, was nicht gut funktioniert hat und jetzt antworte ich nur blind :(Deine Lösung ist nett, da es viel prägnanter ist. Auch nur count() anstelle von Das Dekodieren von Nullen ist ordentlich und kam mir nicht in den Sinn. – Demo

0

Diese Abfrage gibt alle Datensätze in PlanPlanSet gestellt werden, die nur ausgeschlossener Pläne Sätze:

select * from PlanPlanSet pss 
where not exists 
    (select planname from planPlanSet x 
    where x.setname = pss.setname 
    minus 
    select planname from ExcludedPlans) 
/

der MINUS Operator erzeugt einen Satz von Datensätzen aus der oberen Unterabfrage, die in der unteren Unterabfrage nicht existieren. Wenn das Ergebnis ein leerer Satz ist, enthält der Plansatz nur ausgeschlossene Pläne. MINUS ist keine sehr schnelle Operation, daher ist dies möglicherweise nicht der beste Ansatz, wenn Sie eine große Anzahl von zu verarbeitenden Datensätzen haben. Es hat jedoch den Vorteil, Spalten von PlanPlanSet, nicht nur die setname abrufen.

LiveSQL demo.