2013-06-07 7 views
7

Ich bin irgendwie fest. Ich möchte ein Benutzer-Rollen-Beziehung-Pivot-Tabelle zu tun, und meine Frage so sieht weit wie folgt aus:Dynamic Oracle Pivot_In_Clause

WITH PIVOT_DATA AS (
    SELECT * 
    FROM 
    (
     SELECT USERNAME, GRANTED_ROLE 
     FROM [email protected]_LINK U LEFT OUTER JOIN [email protected]_LINK R 
     ON U.USERNAME = R.GRANTEE 
    ) 
) 
SELECT * 
FROM PIVOT_DATA 
PIVOT 
(
    COUNT(GRANTED_ROLE) 
    FOR GRANTED_ROLE 
    IN('CONNECT') -- Just an example 
) 
ORDER BY USERNAME ASC; 

Es funktioniert wirklich gut und macht den Job, aber ich will keine Rolle, die ich zu schreiben, schreiben wollen in der pivot_in_clause suchen, weil wir wie Tonnen von ihnen bekommen haben und ich nicht jedes Mal überprüfen möchte, ob es irgendwelche Änderungen gibt.

Also gibt es eine Möglichkeit, eine SELECT in der pivot_in_clause zu schreiben? Ich habe versucht, es selbst:

[...] 
PIVOT 
(
    COUNT(GRANTED_ROLE) 
    FOR GRANTED_ROLE 
    IN(SELECT ROLE FROM [email protected]_LINK) 
) 
[...] 

Aber es gibt mir immer ein ORA-00936: „missing Ausdruck“ in Zeile 1 der gesamten Abfrage und ich weiß nicht, warum. Kann es nicht eine SELECT in der pivot_in_clause oder mache ich es falsch?

+0

Die Problem mit Ihrem Wunsch ist, dass die Anzahl der Spalten des Ergebnisses unvorhersehbar/variabel ist. –

+0

@FlorinGhita: Ja, ich muss dieses Skript auf 5 verschiedenen Datenbankinstanzen ausführen und die Anzahl der Rollen ist unterschiedlich. Deshalb wollte ich eine "dynamische" Version dieses Skripts haben. –

+3

Sie können PIVOT XML verwenden und dann (any) als Ihre Klausel verwenden. Der Nachteil ist, dass es dann an Ihrem Client liegt, das XML zu parsen. – dazedandconfused

Antwort

6

Sie dynamische Abfrage in Ihrem Skript bauen, Blick auf dieses Beispiel:

variable rr refcursor 

declare 
    bb varchar2(4000); 
    cc varchar2(30000); 
begin 
    WITH PIVOT_DATA AS (
     SELECT * 
     FROM 
     (
      SELECT USERNAME, GRANTED_ROLE 
      FROM DBA_USERS U LEFT OUTER JOIN DBA_ROLE_PRIVS R 
      ON U.USERNAME = R.GRANTEE 
     ) 
    ) 
    select ''''|| listagg(granted_role, ''',''') 
      within group(order by granted_role) || '''' as x 
    into bb 
    from (
     select distinct granted_role from pivot_data 
    ) 
    ; 

    cc := q'[ 
    WITH PIVOT_DATA AS (
     SELECT * 
     FROM 
     (
      SELECT USERNAME, GRANTED_ROLE 
      FROM DBA_USERS U LEFT OUTER JOIN DBA_ROLE_PRIVS R 
      ON U.USERNAME = R.GRANTEE 
     ) 
    ) 
    SELECT * 
    FROM PIVOT_DATA 
    PIVOT 
    (
     COUNT(GRANTED_ROLE) 
     FOR GRANTED_ROLE 
     IN(]' || bb || q'[) -- Just an example 
    ) 
    ORDER BY USERNAME ASC]'; 

    open :rr for cc; 
end; 
/

SET PAGESIZE 200 
SET LINESIZE 16000 
print :rr 

Hier ist das Ergebnis (nur kleines Fragment, denn es ist sehr breit und lang ist)

----------------------------------------------------------------------------------------------------------------------------------- 
    USERNAME      'ADM_PARALLEL_EXECUTE_TASK' 'APEX_ADMINISTRATOR_ROLE' 'AQ_ADMINISTRATOR_ROLE' 'AQ_USER_ROLE'   
    ------------------------------ --------------------------- ------------------------- ----------------------- ---------------------- 
    ANONYMOUS      0       0       0      0   
    APEX_030200     0       0       0      0   
    APEX_PUBLIC_USER    0       0       0      0  
    APPQOSSYS      0       0       0      0 
.............. 
    IX        0       0       1      1 
    OWBSYS       0       0       1      1  
+0

Oh wow, danke einen Haufen. Das war genau das, wonach ich gesucht habe. Es macht wirklich einen tollen Job. :) –