Oracle - 循环列表

时间:2017-07-11 14:38:02

标签: oracle cursor

我有一个基本的SQL查询,我希望将其变成动态游标。

我有一个列列表,我正在检查以查看自上次运行以来值是否已更改,我正在检查的列包括:收入,种族等。

之前和之后的值的输出需要存储在临时表或永久表中以供进一步调查 - 例如价值变化的来源等......

因为列的列表超过600+,我不认为我想编译基本SQL 600次..

是否有更好的方法来编写动态SQL游标来完成此任务? 谢谢!

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

---期望的输出

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

1 个答案:

答案 0 :(得分:0)

这是让你入门的东西。它不是用600个联合生成一个巨大的查询,而是生成600个查询并按顺序运行它们。您需要添加代码以将每次迭代的结果保存到另一个表中:

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;