表的循环列的Oracle结构
Posted
技术标签:
【中文标题】表的循环列的Oracle结构【英文标题】:Oracle Structure for loop column of table 【发布时间】:2020-11-06 16:54:56 【问题描述】:在工作中,他们开发了一段代码,在其中声明了一个具有 %ROWTYPE 的表(该表有 243 列),并为每一列插入了一个值。
我的表
COL_001 VARCHAR2(4000)
COL_002 VARCHAR2(4000)
..
COL_243 VARCHAR2(4000)
如您所见,它们都是 VARCHAR2。创建此表是因为数据是从 csv 文件中读取然后插入到该表中的。
代码:
CREATE OR REPLACE PROCEUDRE AS TEST
v_rec MYTABLE%ROW_TYPE;
BEGIN
v_rec.COL001 := value;
v_rec.COL002 := value;
...
v_rec.COL243 := value;
END TEST;
是否可以使用其他数据结构创建循环?
CREATE OR REPLACE PROCEUDRE AS TEST
v_rec MYTABLE%ROW_TYPE;
BEGIN
for i in 1..243 loop
v_rec.i:= value;
end loop;
END TEST;
【问题讨论】:
“创建此表是因为从 csv 文件中读取数据,然后将其插入该表。” 换句话说,创建此表是因为没有人愿意使用 Oracle 的内置功能,例如 SQL*Loader 或外部表。 【参考方案1】:这就是我理解问题的方式 - 你会使用 collections。
样本表;我不想创建一个有 200 列的表,所以 - 3 就行了。
SQL> select * from test;
COL_001 COL_002 COL_003
---------------------------------------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
PL/SQL 代码:
SQL> set serveroutput on
SQL> declare
2 -- this is were you'll store contents of the table
3 type testtype is table of test%rowtype index by pls_integer;
4 test_tab testtype;
5 begin
6 -- fetch table contents into TEST_TAB
7 select *
8 bulk collect into test_tab
9 from test;
10
11 -- you'd do something with it; I'm just displaying some values
12 for i in test_tab.first .. test_tab.last loop
13 dbms_output.put_line(test_tab(i).col_001 ||' '|| test_tab(i).col_002);
14 end loop;
15 end;
16 /
10 ACCOUNTING
20 RESEARCH
30 SALES
40 OPERATIONS
PL/SQL procedure successfully completed.
SQL>
【讨论】:
【参考方案2】:遍历列,您可以使用 dbms_sql 实用程序 这是一个例子
DROP TABLE ABC;
CREATE TABLE ABC (COL1, COL2, COL243) AS
SELECT '1001', 'LO SABIA', 'I KNEW IT' FROM DUAL UNION
SELECT '1002', 'NO IMPORTA','IT DOES NOT MATTER' FROM DUAL;
/
DECLARE
--
l_query VARCHAR2(4000) := 'Select * from abc';-------------replace table name to test
l_thecursor INTEGER DEFAULT dbms_sql.open_cursor;
l_columnvalue VARCHAR2(4000);
l_status INTEGER;
l_colcnt NUMBER := 0;
l_separator VARCHAR2(1) := '|';
l_desctbl dbms_sql.desc_tab;
l_insert_col_list VARCHAR2(3000);
l_insert_row_line VARCHAR2(3000);
l_insert_data_line VARCHAR2(3000);
TYPE numberstab IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
l_col_pad numberstab; --column size
--
BEGIN
dbms_sql.parse(l_thecursor, l_query, dbms_sql.native);
l_status := dbms_sql.execute(l_thecursor);
--
--describe columns
dbms_sql.describe_columns(l_thecursor, l_colcnt, l_desctbl);
FOR i IN 1 .. l_colcnt
LOOP
l_col_pad(i) := greatest(l_desctbl(i).col_name_len,
CASE l_desctbl(i).col_type
WHEN 12 --date
THEN
10
WHEN 2 THEN --number
6
ELSE
greatest(l_desctbl(i).col_max_len, 4)
END);
l_insert_col_list := l_insert_col_list || l_separator ||
lpad(l_desctbl(i).col_name, l_col_pad(i), ' ');
l_insert_row_line := l_insert_row_line || '+' || lpad('-', l_col_pad(i), '-');
dbms_sql.define_column(l_thecursor, i, l_columnvalue, 4000);
END LOOP;
--
l_insert_row_line := l_insert_row_line || '+';
dbms_output.put_line(l_insert_row_line);
dbms_output.put_line(l_insert_col_list || '|');
dbms_output.put_line(l_insert_row_line);
--
--ROWS
WHILE (dbms_sql.fetch_rows(l_thecursor)) > 0
LOOP
--COLUMNS
FOR i IN 1 .. l_colcnt
LOOP
dbms_sql.column_value(l_thecursor, i, l_columnvalue);--retrieve column value
--replace this section with the code you need
IF l_columnvalue IS NULL
THEN
l_insert_data_line := l_insert_data_line || l_separator ||
lpad('Null', l_col_pad(i), ' ');
ELSIF l_desctbl(i).col_type IN (12)
THEN
l_insert_data_line := l_insert_data_line || l_separator ||
lpad(to_char(to_date(l_columnvalue, 'dd-mon-yy'), 'yyyy-mm-dd'),
l_col_pad(i), ' ');
ELSE
l_insert_data_line := l_insert_data_line || l_separator ||
lpad(l_columnvalue, l_col_pad(i), ' ');
END IF;
END LOOP;
dbms_output.put_line(l_insert_data_line || '|');
l_insert_data_line := '';
--
END LOOP;
dbms_output.put_line(l_insert_row_line);
dbms_sql.close_cursor(l_thecursor);
END;
这将产生以下输出
+----+----------+------------------+
|COL1| COL2| COL243|
+----+----------+------------------+
|1001| LO SABIA| I KNEW IT|
|1002|NO IMPORTA|IT DOES NOT MATTER|
+----+----------+------------------+
【讨论】:
【参考方案3】:方法: 第 1 步 - 将列名从元数据中提取为字符串。使用 XMLAGG 将行转换为列。
select
rtrim (xmlagg (xmlelement (e, column_name || ',') order by column_name).extract ('//text()'),',')
into lv_columns from
(select table_name,column_name from user_Tab_columns where table_name ='TESTTAB'
order by column_name asc) tab
group by
table_name;
第 2 步 - 使用 CONNECT BY LEVEL 根据列数生成序列号。再次使用 XMLAGG 将结果行转换为列并将其提取为字符串。根据需要将 4 的数字更改为 243。
select
rtrim (xmlagg (xmlelement (e, level || ',')).extract ('//text()'),',')
into lv_values FROM dual
CONNECT BY level < 4
;
第 3 步 - 使用从第 2 步提取的值为第 1 步中的列的插入制定查询。
lv_query := 'insert into TESTTAB ('||lv_columns||') values ('||lv_values||')';
第 4 步 - 使用 EXECUTE IMMEDIATE 执行插入查询。
execute immediate lv_query;
有关完整的解决方案,请参阅 DBFIDDLE 链接 - https://dbfiddle.uk/?rdbms=oracle_18&fiddle=edcc497332e87c50273369440646e402
【讨论】:
【参考方案4】:也许这就是你要问的?
create or replace package test_pkg as
v_rec mytable%rowtype;
procedure proc;
end test_pkg;
/
create or replace package body test_pkg as
procedure proc is
begin
for i in 1 .. 243 loop
execute immediate 'begin
test_pkg.v_rec.col_' || lpad(i, 3, '0') || ' := :x;
end;'
using value;
end loop;
end proc;
end test_pkg;
/
【讨论】:
以上是关于表的循环列的Oracle结构的主要内容,如果未能解决你的问题,请参考以下文章
如何从 oracle sql 中的一个列结构创建多个列的视图?
oracle exp不能导出空表,怎样才能导出空表的结构呢?imp怎么导入空表结构?
Oracle loop循环while循环for循环if选择和case选择更改读取数据游标触发器存储过程