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

Posted

技术标签:

【中文标题】在每次循环迭代中更改记录字段【英文标题】:Change record field in each loop iteration 【发布时间】:2017-11-15 15:24:25 【问题描述】:

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

我设法创建了这个查询:

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;

我创建了以下 sn-p:

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 时出现以下错误:

    00000 - “SQL 命令未正确结束” *原因: *行动:

    00000 - “%s:无效标识符” *原因: *行动:

ORA-00911: 无效字符

当我尝试创建动态查询时,一切似乎都崩溃了。我该如何解决这个问题?我应该继续动态查询还是有更简单的方法来更改v_dwrecord."2009"

样本输出:

【问题讨论】:

显示示例输出。有比使用您发布的代码块更好的方法 我添加了示例输出的图像。 【参考方案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>;

【讨论】:

这个选择返回的正是我需要的!我需要将所有这些数据放在一个表中并返回它。我的旧解决方案是一个包含 t_DWRECORD 记录的表。将您的选择转换为表格的最有效方法是什么? 您可以创建一个函数并将其作为游标返回。看到这个线程:***.com/questions/2829880/…【参考方案2】:

我认为您可以使用 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

【讨论】:

以上是关于在每次循环迭代中更改记录字段的主要内容,如果未能解决你的问题,请参考以下文章

当我们正在循环的迭代在每次迭代中被修改时,循环的行为是啥[重复]

如何创建一个循环来检查每次迭代时是不是有新的 IBAction 输入?

如何在C中创建连续循环,其中循环的每次迭代在其内部循环的每次迭代中发生一次

在 foreach 循环中每次迭代后 PHP 回显

for 循环是不是在每次迭代中重新评估其主体中的函数?

在tomcat中的每次循环迭代中,JPA查询变慢