【问题标题】:Oracle - Derived table, Inserting values into a new tableOracle - 派生表,将值插入新表
【发布时间】:2021-06-19 13:34:10
【问题描述】:

我有一个函数可以读取字段中的逗号分隔值列表。此函数的结果将创建一个派生表。

例子:

派生表:

现在,我需要将此数据插入到一个新的/现有的表中。我创建了包含派生表中所有列的对象类型/包,但是,我不确定如何添加/引用这些数据以便能够插入到新表/现有表中。

【问题讨论】:

  • 我认为您混淆了派生表(您从中读取的查询)和嵌套表(表中的表)。您想要存储由普通列(数字、日期、字符串)和嵌套表列组成的查询结果。您想知道如何存储它。对吗?
  • 对不起,是的,表中的表。抱歉,我最初并不清楚。我能够解析具有 CSV 数据的列。我必须创建一个函数来解析这个并且不计算双引号之间的逗号。我能够做到这一点。但是,这在我的表中创建了一个嵌入式表。我需要将该嵌入表标准化为它自己的列。我试图绕过所有这些并使用正则表达式,但是,我无法始终如一地允许空值,也无法将逗号列表留在双引号内,但最终还是得到了我期望的 48 列。

标签: sql oracle oracle11g


【解决方案1】:

通过使用TABLE 函数从表函数中进行选择,可以将返回嵌套表的函数转换为常规行和列。 (在最新版本的 Oracle 中,TABLE 运算符是可选的。)

例如:

SQL> create or replace function get_columns return sys.odcivarchar2list is
  2  begin
  3      return sys.odcivarchar2list('355352', 'Yes');
  4  end;
  5  /

Function created.

SQL> select column_value from table(get_columns);

COLUMN_VALUE
--------------------------------------------------------------------------------
355352
Yes

现在该函数可以在任何地方使用,例如插入:insert into some_table select column_value from table(get_columns);

如果结果包含多个列,或者您有多个结果集等,您的具体解决方案可能会更复杂。如果您仍需要帮助,请使用有关函数和类型的更多详细信息编辑您的问题。


编辑:下面是在列中存储 CSV 值的完整示例,创建一个将 CSV 转换为 VARRAY 的函数,调用该函数进行旋转,然后再次旋转回多个列:

create table table_1
(
    request_id number,
    service varchar2(100),
    method varchar2(100),
    request_date date,
    process_date date,
    te_suid number,
    status varchar2(100),
    params varchar2(4000)
);

create or replace type params_varray is varray(48) of varchar2(4000);

--Example function that converts comma-separated lists into VARRAYS.
--(Not tested for nulls, consecutive commas, etc.)
create or replace function get_columns(p_params varchar2, p_delimiter varchar2) return params_varray is
    v_array params_varray := params_varray();
begin
    for i in 1 .. regexp_count(p_params, p_delimiter) + 1 loop
        v_array.extend;
        v_array(v_array.count) := regexp_substr(p_params, '[^'||p_delimiter||']+', 1, i);
    end loop;

    return v_array;
end;
/

insert into table_1 values(1,1,1,sysdate,sysdate,1,1,'1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48');
insert into table_1 values(2,2,2,sysdate,sysdate,2,2,'49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96');


--Convert CSV into multiple columns.
--
--Convert rows back into multiple columns.
select request_id, service, method, request_date, process_date, te_suid, status
    ,max(case when param_index = 1 then param_value else null end) value1
    ,max(case when param_index = 2 then param_value else null end) value2
    ,max(case when param_index = 3 then param_value else null end) value3
    --Repeat for 4 through 48.
from
(
    --Convert CSV to rows.
    select request_id, service, method, request_date, process_date, te_suid, status,
        row_number() over (partition by table_1.rowid order by rownum) param_index,
        column_value param_value
    from table_1
    cross join get_columns(table_1.params, ',')
)
group by request_id, service, method, request_date, process_date, te_suid, status;

您可以在db<>fiddle 上运行示例。

但是,如果您对此有任何选择,我强烈建议您对表进行非规范化,并且永远不要将分隔值存储在数据库中。

【讨论】:

  • 谢谢你,乔恩。我明白这一点。我不确定如何重新加入 7 列的原始表。例如,在我的示例中,我有 7 列和派生表。我需要同一行中的所有内容,即开头的 7 列,以及作为派生表一部分的 48 列。使用 table 语句将以行格式为我提供派生表中的数据,但我需要对数据进行透视,以便我有 2 行和 55 列(7 来自常规选择 + 48 来自派生表)
  • 这是我的完整选择:选择 a.request_id、--1 a.service、--2 a.method、--3 a.request_date、--4 a.process_date、--5 a .te_suid, --6 a.status --7 get_columns(a.params,',','\"') -- 有 48 行,2 列(索引,值)来自 table_1 a WHERE a.method = 'saveCobqResponse ' AND a.params like '%355352%' AND a.params like '%2021%'; 返回数据应该是 2 行 55 列,以便我可以选择/插入另一个表。谢谢!
  • @user3874930 嵌套表是否总是最多包含 48 行,还是该值是动态的?动态旋转会使这个问题变得更加困难。
  • 总是 48。可能有空值,但派生表中应该总是有 48 行。
  • 谢谢你,乔恩。我希望我可以让团队改变他们的流程并且不将值存储为 CSV,但这是遗留问题,并且该团队在 5 年前离开了,所以我一直在尝试解析这个字段。这至少给了我一个起点。我创建了几个函数和类型,但总是以一种奇怪的方式得到结果。我会处理这个并相应地更新你!
猜你喜欢
  • 2017-04-19
  • 1970-01-01
  • 1970-01-01
  • 2021-02-25
  • 2015-10-16
  • 2012-07-25
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
相关资源
最近更新 更多