用于列的 Oracle 动态 SQL
Posted
技术标签:
【中文标题】用于列的 Oracle 动态 SQL【英文标题】:Oracle Dynamic SQL for columns 【发布时间】:2009-11-04 00:32:52 【问题描述】:我正在编写一个存储过程,我需要根据所报告的数据填充一个表。
在这种情况下,我将每天为某个日期范围内的某个代码提取三个值。
假设在这个存储过程的某个运行中,我有一个日期范围的代码值 X、Y 和 Z:
select abc.code,
abc.date,
abc.val_1,
abc.val_2,
abc.val_3
from data.abc
where abc.date BETWEEN '01-OCT-2009' AND '31-OCT-2009'
因此,对于日期范围内的每一天,我都有代码 x、y 和 z 的三个记录。
在我的最终表格中,我需要将其从行转换为列。通常我会使用解码功能,但这里我想根据返回的数据动态创建最终表格。
在这种情况下,我将在该范围内的每一天都有一条记录,并且还有 9 列(val_1_X、val_2_x、val_3_x、val_1_y 等等)。
我想动态设置它,这样当引入新的“代码”时我不需要重新打开我的存储过程,这样在报告的每个实例上,只返回“代码”该报告实例包含在决赛桌中。
这可以通过动态sql实现吗?我使用的是 Oracle 版本 10g。
【问题讨论】:
我建议让报告工具做任何交叉表/立方体/数据透视,只担心查询返回正确的数据来支持它。 【参考方案1】:据我了解,01-OCT-2009 到 31-OCT-2009 只有代码 x、y 和 z,而去到 2009 年 11 月 30 日也可能会为您带来w。
最终,您需要这样的查询:
CREATE TABLE t1 AS
SELECT
abc.date,
MAX(DECODE(code, 'x', val_1, NULL)) AS abc_val_1_x,
MAX(DECODE(code, 'x', val_2, NULL)) AS abc_val_2_x,
MAX(DECODE(code, 'x', val_3, NULL)) AS abc_val_3_x,
MAX(DECODE(code, 'y', val_1, NULL)) AS abc_val_1_y,
MAX(DECODE(code, 'y', val_2, NULL)) AS abc_val_2_y,
MAX(DECODE(code, 'y', val_3, NULL)) AS abc_val_3_y,
...
FROM data.abc
WHERE abc.date BETWEEN '01-OCT-2009' AND '31-OCT-2009'
GROUP BY abc.date
我不是 Oracle 人员,也无权在 Oracle 上进行测试,因此您可能会在下面发现不少语法错误等。您还需要将硬编码日期更改为变量,声明一些变量并实际运行创建的查询。
-- Figure out all valid codes for date range.
-- Might also require ordering depending on your report.
CURSOR c1
IS
SELECT
abc.code
FROM data.abc
WHERE abc.date BETWEEN '01-OCT-2009' AND '31-OCT-2009'
GROUP BY abc.code;
query1 := 'CREATE TABLE abc_report AS SELECT date';
LOOP
FETCH c1 INTO code1
EXIT WHEN c1%NOTFOUND;
query1 := query1 || ', DECODE(code, ''' || code1 || ''', val_1, NULL)) AS abc_val_1_' || code1 ||
', DECODE(code, ''' || code1 || ''', val_2, NULL)) AS abc_val_2_' || code1 ||
', DECODE(code, ''' || code1 || ''', val_3, NULL)) AS abc_val_3_' || code1
END LOOP;
query1 := query1 || ' FROM data.abc WHERE date BETWEEN ''01-OCT-2009'' AND ''31-OCT-2009'''
【讨论】:
【参考方案2】:非常感谢您的帮助,但事实证明我终究无法走这条路。存储过程将由报告工具启动并使用,我需要为该报告的多个实例将同时运行的可能性做好准备,所以我不能重复使用表名,我会的不允许有一个存储过程来为每个运行实例创建一个唯一的表。
再次感谢您的帮助!
【讨论】:
您好!欢迎来到 ***!这是对 lins314159 的回答的回应吗? *** 只通知 cmets 的用户他们的答案。除非他重新审视这个问题,否则他不会知道你做出了这个决定。同样,lins314159 的回答是否真的解决了 original 问题?如果是这样,您可以考虑接受他的回答以换取他的努力。之后! :)【参考方案3】:对于多个实例,使用全局临时表,并根据要求在提交删除行或提交保留时使用选项。无论选项如何,记录都将仅适用于该会话。
【讨论】:
以上是关于用于列的 Oracle 动态 SQL的主要内容,如果未能解决你的问题,请参考以下文章
Left Join 不返回丢失的信息 - SQL Oracle