在每次循环迭代中更改记录字段
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 IMMEDIATE
与VARCHAR2(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 collect
和 pivot
来做到这一点,就像这里:
样本数据:
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 输入?