2017-04-11 1 views
0

Ich habe 3 Tabellen in einer Oracle-Datenbank. Sie sehen wie folgt aus:Die von listagg in einer where-Klausel generierte Spalte

Table User: 

username|forename|surname 
a   a  a 
b   b  b 
c   c  c 


Table Right: 

username|organisationname|right 
a   x    user 
a   x    admin 
a   x    owner 
a   y    user 
a   y    admin 
a   z    owner 
b   x    user 
c   y    user 
c   y    admin 
c   z    user 

Table Organisation: 

organisationname|number 
x     12 
y     14 
z     42 

Die Tabelle Right hat zwei FOREIGN_KEYS: username Punkte auf die Säule mit dem gleichen Namen in der Tabelle user und organisationname auf den Tisch Organisation.

Für alle user, die den richtigen Benutzer auf organisation x haben, möchte ich eine Liste aller organisations erhalten (ausgenommen Organisation x), wo der Benutzer hat 1 oder mehr Rechte.

In meinem Beispiel: a hat rechten Benutzer auf x, b hat rechten Benutzer auf x, c hat nicht den richtigen Benutzer auf x. Also ich will nur alle Organisationen (distinct !, kein Organisationsname zweimal) für Benutzer a und b (und nicht für c !!!). Wenn ein Benutzer kein Recht auf eine andere Organisation als x hat (wo er den richtigen Benutzer haben muss), möchte ich diesen Benutzer in der Ausgabe, aber ohne Organisation.

Die erwartete Ausgabe lautet:

user|organisations 
a y; z 
b 

Ich hoffe, Sie verstehen, was ich meine. Meine Abfrage so weit ist die folgende:

select username, 
/* listagg put all the organisationnames of one user in one column separated by ; 
    then the organsation x gets removed from the result*/ 
regexp_replace (listagg (organisationname, '; ') 
     within group (order by organisationname), '(^x;?)|(?x;)|(; x$) ', '') as "organisations" 
from(
    select u2.username as username, 
      o.organisationname as organisationname, 
      /*I do this to remove duplicate entries in the list of organisations of one user */ 
      row_number() over (partition by u2.username, o.organisationname order by u2.username) as rn 
     from RIGHT r2, ORGANISATION o, USER u2 
     where r2.organisationname = o.organisationname 
     and r2.username = u2.username 
     and r2.username IN 
      (
      select u.username 
      from USER u, right r 
      where r.username = u.username 
      and r.right = 'user' 
      ) 
    order by u2.username, o.organisationname   
) 
where rn = 1 
group by username 

Diese Abfrage funktioniert, aber jetzt möchte ich auf die Spalten Organisationen filtern. Aber ich kann es nicht in der Where-Klausel verwenden. Wenn ich versuche, es zu verwenden, löst Orakel den Fehler aus: ORA-00904: ungültiger Bezeichner

Weiß jemand, wie ich das erreichen kann? Ich denke Orakel hat Probleme wegen der analytischen Funktion listagg. Ich würde mich auch über Vorschläge freuen, wie ich meine Abfrage vereinfachen kann. Vielen Dank! Hier

ist, was ich versucht, die Spalte Organisationen in der where-Klausel zu verwenden:

select * from (***long query shown above***) 
where organisations like '%termToSearch%'; 
+0

Können Sie auch posten, was versuchst du derzeit, was dir den fehler –

+0

gibt stelle ich eine frage mit dem where-satz am ende meiner frage – Markus

Antwort

2

Schritt für Schritt: Benutzernamen für Benutzer | x, dann verschiedene Benutzer | Organisation außer x, dann Aggregations- pro Benutzername:

select 
    username, 
    listagg(organisationname, '; ') within group (order by organisationname) as organisations 
from 
(
    select distinct username, organisationname 
    from right 
    where username in 
    (
    select username 
    from right 
    where organisationname = 'x' and right = 'user' 
) 
    and organisationname <> 'x' 
) 
group by username; 

(Leider nimmt LISTAGG kein DISTINCT Schlüsselwort, also müssen wir zwei Schritte statt einer Liste von verschiedenen Organisationen zu bauen.)

UPDATE: Benutzer ohne jede andere Organisation zu erhalten, auch, würden wir den Zustand and organisationname <> 'x' entfernen und in einem Fall hinzufügen konstruieren zu LISTAGG:

select 
    username, 
    listagg(case when organisationname <> 'x' then organisationname end, '; ') 
    within group (order by organisationname) as organisations 
from 
(
    select distinct username, organisationname 
    from right 
    where username in 
    (
    select username 
    from right 
    where organisationname = 'x' and right = 'user' 
) 
) 
group by username; 
+0

Danke Thorsten. Ihre Abfrage sieht viel einfacher aus als meine Abfrage (und ich kann die Organisation in der where-Klausel verwenden). Aber ich denke, Ihre Anfrage gibt mir nicht das richtige Ergebnis. In meinem Beispiel habe ich Benutzer b, der den richtigen Benutzer für Organisation x hat, aber kein Recht für andere Organisationen. Ich möchte diesen Benutzer in meiner Ausgabe haben (ohne irgendeine Organisation). Mit Ihrer Abfrage ist dieser Benutzer nicht in der Ausgabe, weil Sie nur nach Rechten suchen, die nicht auf Organisation x sind. – Markus

+0

Sie haben Recht. Ich habe eine Abfrage hinzugefügt, die funktionieren sollte. –

+0

Vielen Dank! Es funktioniert jetzt :) – Markus

1

Ändern Sie den Teil des Codes, in dem Sie hinzufügen Alias,

Alte Code -

within group (order by organisationname), '(^x;?)|(?x;)|(; x$) ', '') as "organisations" 

neue Code -

within group (order by organisationname), '(^x;?)|(?x;)|(; x$) ', '') organisations 

oder

neuen Code -

within group (order by organizationname), '(^x;?)|(?x;)|(; x$) ', '') as "ORGANISATIONS" 

Wenn Sie immer noch den alten Code verwenden möchten, können Sie die letzte ändern, in dem Zustand, wie -

where "organisations" like '%termToSearch%'; 

Referenz: Schema Object Names and Qualifiers

+0

Danke! Beide Lösungen funktionieren! Können Sie mir bitte erklären, warum es funktioniert, wenn ich "ORGANISATIONEN" mit Großbuchstaben anstelle von Kleinbuchstaben schreibe? – Markus

+0

@Markus - Aktualisierte Antwort, Der Referenzlink erläutert, wie Datenbankobjekte benannt und gespeichert werden. –

+1

@Markus: Mit Anführungszeichen teilen Sie dem DBMS mit, dass Sie Groß- und Kleinschreibung beachten müssen. Ohne Anführungszeichen Oracle speichert Namen intern in Großbuchstaben. Deshalb sind Organisationen = ORGANISATIONEN = Organisationen = "ORGANISATIONEN" <> "Organisationen". (Das 'as' macht übrigens keinen Unterschied.) –

Verwandte Themen