2013-06-07 14 views
7

Trochę utknąłem. Chcę zrobić tabelę użytkownika role-relacja obrotu i moje zapytanie do tej pory wygląda następująco: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; 

To działa bardzo dobrze i spełnia swoje zadanie, ale nie chcę pisać napisać żadnej roli I chcesz wyszukać w pivot_in_clause, ponieważ mamy ich tonę i nie chcę za każdym razem sprawdzać, czy są jakieś zmiany.

Więc czy istnieje sposób na napisanie SELECT w pivot_in_clause? Próbowałem sobie:

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

Ale to zawsze daje mi ORA-00936: „brakujące wyrażenie” w wierszu 1 całego zapytania i nie wiem dlaczego. Czy nie może być SELECT w pivot_in_clause lub czy robię to źle?

+0

The Problem z twoim pragnieniem polega na tym, że liczba kolumn wyniku jest nieprzewidywalna/zmienna. –

+0

@FlorinGhita: Tak, muszę uruchomić ten skrypt w 5 różnych instancjach bazy danych, a liczba ról jest inna. Dlatego chciałem mieć "dynamiczną" wersję tego skryptu. –

+3

Możesz użyć PIVOT XML, a następnie użyć (any) jako klauzuli. Wadą jest to, że to do klienta należy przeanalizować xml. – dazedandconfused

Odpowiedz

6

Można budować dynamiczną kwerendę w skrypcie, spojrzenie na ten przykład:

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 

Oto wynik (tylko mały fragment, ponieważ jest bardzo szeroka i długa)

----------------------------------------------------------------------------------------------------------------------------------- 
    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

Och, dziękuję, dzięki. Dokładnie to, czego szukałem. To naprawdę robi niesamowitą robotę. :) –