用于列的 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 只有代码 xyz,而去到 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的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL Oracle 的 B 列中搜索 A 列的每个值

Left Join 不返回丢失的信息 - SQL Oracle

Oracle 执行动态语句

Oracle中动态SQL详解(EXECUTE IMMEDIATE)

oracle静态sql和动态sql

PL/SQL Oracle 11g 记录组