2013-03-19 9 views
6

... Pivot (sum (A) für die in B (X))Schwenk in Oracle SQL

Nun B ist der Datentyp varchar2 und X eine Kette von varchar2 durch Kommata getrennte Werte.
Werte für X sind verschiedene Werte aus einer Spalte (sagen CL) der gleichen Tabelle. Auf diese Weise funktionierte die Pivot-Abfrage.

Aber das Problem ist, dass, wenn es ein neuer Wert in der Spalte CL ich manuell, dass X auf den String hinzufügen

Ich versuchte X mit ausgewählten unterschiedlichen Werten von CL zu ersetzen. Aber Abfrage läuft nicht.
Der Grund, den ich fühlte, war aufgrund der Tatsache, dass für das Ersetzen von X wir Werte benötigen, die durch Kommata getrennt sind.
Dann habe ich eine Funktion erstellt, um die exakte Ausgabe zurückzugeben, damit sie mit der Zeichenkette X übereinstimmt. Aber die Abfrage läuft immer noch nicht.
Die angezeigten Fehlermeldungen sind wie "fehlende Righhr-Klammern", "Ende der Datei Kommunikationskanal" usw.
Ich habe versucht, Pivot-XML anstelle von nur Pivot, die Abfrage läuft aber vaues wie oraxxx etc, die überhaupt keine Werte sind .

Vielleicht verwende ich es nicht richtig.
Können Sie mir eine Methode zum Erstellen eines Pivots mit dynamischen Werten mitteilen?

Antwort

6

Sie können keine nicht konstante Zeichenfolge in die IN-Klausel der Pivot-Klausel einfügen.
Sie können Pivot XML dafür verwenden.

Von documentation:

subquery A subquery is used only in conjunction with the XML keyword. When you specify a subquery, all values found by the subquery are used for pivoting

Es sollte wie folgt aussehen:

select xmlserialize(content t.B_XML) from t_aa 
pivot xml(
sum(A) for B in(any) 
) t; 

Sie können auch eine Unterabfrage anstelle des ANY Schlüsselwort:

select xmlserialize(content t.B_XML) from t_aa 
pivot xml(
sum(A) for B in (select cl from t_bb) 
) t; 

Here is a sqlfiddle demo

+0

hallo Ihre Methode tatsächlich funktioniert, aber Ausgang i im XML-Format immer bin. Kann ich als Tabelle mit Zeilen und Spalten ausgegeben werden? – prabhakar

+0

AFAIK, nicht dynamisch ... Aber wie wollen Sie ein Ergebnis verwenden, dessen Struktur Sie nicht kennen? –

15

Sie können keine dynamische Anweisung in die IN-Anweisung von PIVOT einfügen, ohne PIVOT XML zu verwenden, das weniger als die gewünschte Ausgabe ausgibt. Sie können jedoch eine IN-Zeichenfolge erstellen und sie in Ihre Anweisung eingeben.

Zuerst, hier ist meine Beispieltabelle;

myNumber myValue myLetter 
---------- ---------- -------- 
     1   2 A   
     1   4 B   
     2   6 C   
     2   8 A   
     2   10 B   
     3   12 C   
     3   14 A  

Legen Sie zuerst die Zeichenfolge fest, die in Ihrer IN-Anweisung verwendet werden soll. Hier setzen Sie die Zeichenfolge in "str_in_statement". Wir verwenden COLUMN NEW_VALUE und LISTAGG, um die Zeichenfolge einzurichten.

clear columns 
COLUMN temp_in_statement new_value str_in_statement 
SELECT DISTINCT 
    LISTAGG('''' || myLetter || ''' AS ' || myLetter,',') 
     WITHIN GROUP (ORDER BY myLetter) AS temp_in_statement 
    FROM (SELECT DISTINCT myLetter FROM myTable); 

Ihr String wird wie folgt aussehen:

'A' AS A,'B' AS B,'C' AS C 

nun die String-Anweisung in der PIVOT-Abfrage verwenden.Hier

SELECT * FROM 
    (SELECT myNumber, myLetter, myValue FROM myTable) 
    PIVOT (Sum(myValue) AS val FOR myLetter IN (&str_in_statement)); 

ist der Ausgang: obwohl

MYNUMBER  A_VAL  B_VAL  C_VAL 
---------- ---------- ---------- ---------- 
     1   2   4    
     2   8   10   6 
     3   14     12 

Es Einschränkungen. Sie können nur eine Zeichenfolge bis zu 4000 Byte verketten.

+0

während ich dies versuche, bekomme ich unter oracle error: ORA-56900: Bindevariable wird nicht unterstützt innerhalb der Pivot | pivivot Operation – lourdh

+0

Wie implementiert man dies in Oracle-Prozedur? Bitte geben Sie ein Beispiel – Ram

1

ich das obige Verfahren (Anton PL/SQL benutzerdefinierte Funktion Pivot()) und es die Arbeit erledigt ! Da ich kein professioneller Oracle-Entwickler bin, sind dies einfache Schritte, die ich gemacht habe:

1) Laden Sie das Zip-Paket herunter, um pivotFun.sql dort zu finden. 2) Führen Sie einmal die pivotFun.sql aus, um eine neue Funktion zu erstellen. 3) Verwenden Sie die Funktion in normalem SQL.

Seien Sie vorsichtig mit dynamischen Spaltennamen. In meiner Umgebung habe ich festgestellt, dass der Spaltenname auf 30 Zeichen begrenzt ist und kein einziges Zitat enthalten darf. Also, meine Frage ist jetzt so etwas wie diese:

SELECT 
    * 
FROM 
    table( 
     pivot(' 
       SELECT DISTINCT 
        P.proj_id, 
        REPLACE(substr(T.UDF_TYPE_LABEL, 1, 30), '''''''','','') as Attribute, 
        CASE 
         WHEN V.udf_text is null  and V.udf_date is null and  V.udf_number is NOT null THEN to_char(V.udf_number) 
         WHEN V.udf_text is null  and V.udf_date is NOT null and V.udf_number is null  THEN to_char(V.udf_date) 
         WHEN V.udf_text is NOT null and V.udf_date is null and  V.udf_number is null  THEN V.udf_text 
         ELSE NULL END 
        AS VALUE 
       FROM 
        project P 
       LEFT JOIN UDFVALUE V ON P.proj_id  = V.proj_id 
       LEFT JOIN UDFTYPE T ON V.UDF_TYPE_ID = T.UDF_TYPE_ID 
       WHERE 
        P.delete_session_id IS NULL AND 
        T.TABLE_NAME = ''PROJECT'' 
    ') 
) 

Funktioniert gut mit bis zu 1m Aufzeichnungen.

0

Ich werde nicht genau die Antwort auf die Frage geben, die OP gestellt hat, stattdessen werde ich nur beschreiben, wie dynamisch Pivot gemacht werden kann.

Hier müssen wir dynamisches sql verwenden, indem wir zuerst die Spaltenwerte in eine Variable abrufen und die Variable innerhalb von dynamic sql übergeben.

Beispiel

Betrachten wir wie unten einen Tisch haben.

enter image description here

Wenn wir die Werte in der Spalte YR als Spaltennamen und die Werte in diesen Spalten von QTY zeigen müssen, dann können wir den folgenden Code verwenden.

declare 
    sqlqry clob; 
    cols clob; 
begin 
    select listagg('''' || YR || ''' as "' || YR || '"', ',') within group (order by YR) 
    into cols 
    from (select distinct YR from EMPLOYEE); 


    sqlqry := 
    '  
    select * from 
    (
     select * 
     from EMPLOYEE 
) 
    pivot 
    (
    MIN(QTY) for YR in (' || cols || ') 
)'; 

    execute immediate sqlqry; 
end; 
/

RESULT

enter image description here

Bei Bedarf können Sie auch eine temporäre Tabelle erstellen und eine Auswahlabfrage in dieser temporären Tabelle tun, um die Ergebnisse zu sehen. Es ist einfach, fügen Sie einfach die CREATE TABLE TABLENAME AS in den obigen Code.

sqlqry := 
'  
    CREATE TABLE TABLENAME AS 
    select * from 
0

USE DYNAMIC QUERY

Prüfregeln unter


-- DDL for Table TMP_TEST 
-------------------------------------------------------- 

    CREATE TABLE "TMP_TEST" 
    ( "NAME" VARCHAR2(20), 
    "APP" VARCHAR2(20) 
    ); 
/
SET DEFINE OFF; 
Insert into TMP_TEST (NAME,APP) values ('suhaib','2'); 
Insert into TMP_TEST (NAME,APP) values ('suhaib','1'); 
Insert into TMP_TEST (NAME,APP) values ('shahzad','3'); 
Insert into TMP_TEST (NAME,APP) values ('shahzad','2'); 
Insert into TMP_TEST (NAME,APP) values ('shahzad','5'); 
Insert into TMP_TEST (NAME,APP) values ('tariq','1'); 
Insert into TMP_TEST (NAME,APP) values ('tariq','2'); 
Insert into TMP_TEST (NAME,APP) values ('tariq','6'); 
Insert into TMP_TEST (NAME,APP) values ('tariq','4'); 
/
    CREATE TABLE "TMP_TESTAPP" 
    ( "APP" VARCHAR2(20) 
    ); 

SET DEFINE OFF; 
Insert into TMP_TESTAPP (APP) values ('1'); 
Insert into TMP_TESTAPP (APP) values ('2'); 
Insert into TMP_TESTAPP (APP) values ('3'); 
Insert into TMP_TESTAPP (APP) values ('4'); 
Insert into TMP_TESTAPP (APP) values ('5'); 
Insert into TMP_TESTAPP (APP) values ('6'); 
/
create or replace PROCEDURE temp_test(
    pcursor out sys_refcursor, 
    PRESULT     OUT VARCHAR2 
    ) 
AS 
V_VALUES VARCHAR2(4000); 
V_QUERY VARCHAR2(4000); 
BEGIN 
PRESULT := 'Nothing'; 

-- concating activities name using comma, replace "'" with "''" because we will use it in dynamic query so "'" can effect query. 
    SELECT DISTINCT 
     LISTAGG('''' || REPLACE(APP,'''','''''') || '''',',') 
     WITHIN GROUP (ORDER BY APP) AS temp_in_statement 
    INTO V_VALUES 
    FROM (SELECT DISTINCT APP 
      FROM TMP_TESTAPP); 

-- designing dynamic query 

    V_QUERY := 'select * 
       from ( select NAME,APP 
          from TMP_TEST ) 
       pivot (count(*) for APP in 
        (' ||V_VALUES|| ')) 
      order by NAME' ; 

    OPEN PCURSOR 
    FOR V_QUERY; 


PRESULT := 'Success'; 

Exception 
WHEN OTHERS THEN 
PRESULT := SQLcode || ' - ' || SQLERRM; 
END temp_test;