在每个循环迭代中更改记录字段

时间:2017-11-15 15:24:25

标签: oracle plsql

我必须生成一份报告,显示每个国家/地区的销售额。 (固定年数)

我设法创建了这个查询:

SELECT sum(dwfactsales.amount) as "2009" INTO v_dwrecord."2009"
        FROM dwfactsales
        JOIN dwdimcustomer ON dwdimcustomer.customerkey = dwfactsales.customerkey
        JOIN dwdimdate ON dwdimdate.datekey = dwfactsales.datekey
        WHERE dwdimcustomer.country = 'Australia' and dwdimdate.calenderyear = 2009;
        v_dwreport(1) := v_dwrecord;

此查询非常适合收集2009年澳大利亚的销售额。但是,我想对每年和每个国家/地区使用此查询。我可以迭代这些国家,但我似乎无法重复这些年。

我的记录和表格声明为:

TYPE t_DWRECORD IS RECORD(
    COUNTRY     dwdimcustomer.country%TYPE,
    "2009"      NUMBER,
    "2010"      NUMBER,
    "2011"      NUMBER,
    "2012"      NUMBER,
    "2013"      NUMBER,
    "2014"      NUMBER,
    TOTAL       NUMBER
    );
TYPE t_DWTABLE IS TABLE OF t_DWRECORD INDEX BY BINARY_INTEGER;

我创建了以下代码段:

v_count := 0;
FOR country_rec IN (SELECT DISTINCT country FROM dwdimcustomer order by country asc) LOOP
    FOR year_rec IN (SELECT DISTINCT calenderyear FROM dwdimdate order by calenderyear asc) LOOP
        SELECT sum(dwfactsales.amount) as "2009" INTO v_dwrecord."2009"
        FROM dwfactsales
        JOIN dwdimcustomer ON dwdimcustomer.customerkey = dwfactsales.customerkey
        JOIN dwdimdate ON dwdimdate.datekey = dwfactsales.datekey
        WHERE dwdimcustomer.country = country_rec.country and dwdimdate.calenderyear = year_rec.calenderyear;
        v_dwreport(v_count) := v_dwrecord;
        v_count := v_count+1;
    END LOOP;
END LOOP;

正如您所看到的那样仍然是INTO v_dwrecord."2009"部分,我想在每次迭代中将其更改为year_rec.calenderyear。我怎样才能做到这一点?我尝试将EXECUTE IMMEDIATEVARCHAR2(500)变量一起使用,该变量包含动态查询。它看起来像这样:INTO v_dwrecord." || year_rec.calenderyear ||"

使用EXECUTE IMMEDIATE给了我以下错误:

  
      
  1. 00000 - " SQL命令未正确结束"   *原因:
      *操作:

  2.   
  3. 00000 - "%s:无效的标识符"   *原因:
      *操作:

  4.         

    ORA-00911:无效字符

当我尝试创建动态查询时,一切似乎都会中断。我该如何解决这个问题?我应该继续进行动态查询还是更容易更改v_dwrecord."2009"

示例输出:

enter image description here

2 个答案:

答案 0 :(得分:1)

您可以使用PIVOT技术来完成您想要的操作,而无需使用FOR和RECORD。它会是这样的:

select dwdimcustomer.country,
       sum(case when dwdimdate.calenderyear = 2009 
                  then dwfactsales.amount else 0 end) as "2009",
       sum(case when dwdimdate.calenderyear = 2010 
                  then dwfactsales.amount else 0 end) as "2010",
       ....
       sum(case when dwdimdate.calenderyear = 2014 
                  then dwfactsales.amount else 0 end) as "2014",
       sum(dwfactsales.amount) as total
  FROM dwfactsales
      JOIN dwdimcustomer 
             ON dwdimcustomer.customerkey = dwfactsales.customerkey
      JOIN dwdimdate 
             ON dwdimdate.datekey = dwfactsales.datekey
 GROUP BY dwdimcustomer.country
 ORDER BY <what ever you want here>;

答案 1 :(得分:1)

我认为您可以使用bulk collectpivot来完成此操作,例如:

示例数据:

create table sales as (
  select 'Australia' country, 2009 year, 150 amount from dual union all
  select 'Brasil'    country, 2009 year, 927 amount from dual union all
  select 'Australia' country, 2010 year, 456 amount from dual );

PLSQL块:

declare 
    type t is record(
        country  sales.country%type, 
        s2009    number, 
        s2010    number, 
        total    number);
    type tt is table of t index by binary_integer;

    vtt tt;
begin
    select country, s2009, s2010, nvl(s2009, 0) + nvl(s2010, 0) total
        bulk collect into vtt
        from sales
        pivot (sum(amount) for year in (2009 as s2009, 2010 as s2010));

    -- now you have your collection ready in variable vtt, show some data
    for i in 1..vtt.count loop
        dbms_output.put_line(i);
        dbms_output.put_line(vtt(i).country);
        dbms_output.put_line(' 2009: '||vtt(i).s2009);
        dbms_output.put_line(' 2010: '||vtt(i).s2010);
        dbms_output.put_line('Total: '||vtt(i).total);
    end loop;
end;

结果:

1
Brasil
 2009: 927
 2010: 
Total: 927
2
Australia
 2009: 150
 2010: 456
Total: 606