2017-07-11 8 views
0

Ich habe eine SQL-Basisabfrage, die ich hoffe, in einen dynamischen Cursor zu verwandeln.Oracle - Schleife durch eine Liste von Spalten

Ich habe eine Liste von Spalten, die ich überprüft werde, um zu sehen, ob die Werte seit der letzten Lauf geändert haben, Spalten, die ich überprüft habe umfassen: Einkommen, Herkunft, usw.

Der Ausgang des vor-and- nach Werten müssen in einer temp oder permanenten Tabelle für weitere Untersuchung gespeichert werden - wie Quelle der Wertänderung usw. ...

Da die Liste der Spalten mehr als 600+ ist, glaube ich nicht, dass ich will um die Basis SQL 600 mal zu kompilieren ..

Gibt es eine bessere Möglichkeit, einen dynamischen SQL-Cursor zu schreiben, um diese Aufgabe zu erfüllen?
Danke!

--- Basis SQL

SELECT a.*, 
     'Last_name' AS "field_name", 
     b.LAST_name AS last_name_updated 
from 
    (SELECT person_id, last_name 
    FROM person 
    WHERE batch_id = (select max(batch_id) from person) 
    ) a 
FULL OUTER JOIN 
    (SELECT person_id, last_name 
    FROM person 
    WHERE batch_id = (select max(batch_id) - 1 from person) 
    ) b 
ON a.person_id = b.person_id 
WHERE nvl(a.last_name,0) <> nvl(b.last_nm,0) 

UNION 

SELECT a.*, 
     'Income', 
     b.income AS income_updated 
from 
    (SELECT person_id, income 
    FROM person 
    WHERE batch_id = (select max(batch_id) from person) 
    ) a 
FULL OUTER JOIN 
    (SELECT person_id, income 
    FROM person 
    WHERE batch_id = (select max(batch_id) - 1 from person) 
    ) b 
ON a.person_id = b.person_id 
WHERE nvl(a.income,0) <> nvl(b.income,0) 

--- gewünschter Ausgang

person_id || field_name || previous_value || updated_value 
8783  || income  || 95000   || 98000 
235731  || last_name || Dawson   || Dawson Jr. 

Antwort

0

Hier ist etwas zum Einstieg. Anstatt eine enorme Abfrage mit 600 Unionen zu generieren, erzeugt sie 600 Abfragen und führt sie sequenziell aus. Sie müssten Code hinzufügen, um die Ergebnisse von jeder Iteration zu speichern, vielleicht in eine andere Tabelle:

declare 
    l_sql long; 
    l_default varchar2(10); 
    l_max_batch_id number; 
    rc sys_refcursor; 
begin 
    select max(batch_id) 
    into l_max_batch_id 
    from person; 

    for r in (select column_name, data_type 
       from user_tab_columns 
      where table_name = 'PERSON' 
       and column_name not in ('PERSON_ID') -- Exclude any other columns you don't want to compare 
      ) 
    loop 
    l_sql := q'[SELECT a.person_id, 
         a.col  AS new_value 
         '#COL#' AS column_name, 
         b.#COL# AS old_value 
        from 
         (SELECT person_id, #COL# 
         FROM person 
         WHERE batch_id = #MAXBATCH# 
        ) a 
        FULL OUTER JOIN 
         (SELECT person_id, #COL# 
         FROM person 
         WHERE batch_id = #MAXBATCH#-1 
        ) b 
        ON a.person_id = b.person_id 
        WHERE nvl(a.#COL#,#DEFAULT#) <> nvl(b.#COL#,#DEFAULT#)]'; 

    l_sql := replace (l_sql, '#COL#', r.column_name);     
    l_sql := replace (l_sql, '#MAXBATCH#', l_max_batch_id);     

    l_default := case r.data_type 
        when 'NUMBER' then '0' 
        when 'DATE' then q'[DATE '4000-31-12']' 
        else q'['~~~']' 
        end; 

    l_sql := replace (l_sql, '#DEFAULT#', l_default); 
    open rc for l_sql; 
    -- Now fetch all the data and e.g. write to a table... 
    end loop; 
end; 
+0

Dank @Tony Andrews! Es sieht viel effizienter aus. Der einzige Fehler, den ich bekomme, ist "FROM Schlüsselwort nicht gefunden .... bei Zeile 44" .... Ich überprüfe, um zu sehen, was ich mit dem Code tun muss .. Nochmals vielen Dank! – LycorisRadiata

Verwandte Themen