pl/sql - 集合可以循环遍历列名吗?
下面代码的输出是:
|LAT|MISC|SID|NO
MIN_LENGTH|1|2|1|1
MAX_LENGTH|6|6|4|2
输出如我所料,但是无论如何都可以使用索引(即 j)循环遍历列,而不是执行 RESULTS(I).MAX_LENGTH , RESULTS (I).MAX_LENGTH 等?值得关注的是,当向“R_RESULT_REC”记录添加额外的列时,需要另一个循环。
set serveroutput on
DECLARE
TYPE R_RESULT_REC IS RECORD
(COL_NAME VARCHAR2(100),
MIN_LENGTH NUMBER,
MAX_LENGTH NUMBER
);
TYPE tr_RESULT IS TABLE OF R_RESULT_REC;
RESULTS TR_RESULT := TR_RESULT();
v_counter NUMBER := 1;
BEGIN
FOR J IN (SELECT DISTINCT COLUMN_NAME FROM ALL_TAB_COLUMNS
WHERE OWNER = 'SYSTEM'
and TABLE_NAME = 'SPECCHAR')
LOOP
RESULTS.EXTEND;
RESULTS(V_COUNTER).COL_NAME := J.COLUMN_NAME;
EXECUTE IMMEDIATE 'SELECT MIN(LENGTH('||J.COLUMN_NAME||')),
MAX(LENGTH('||J.COLUMN_NAME||'))
FROM '||'SYSTEM'||'.'||'SPECCHAR' INTO
RESULTS(V_COUNTER).MIN_LENGTH,
RESULTS(V_COUNTER).MAX_LENGTH;
V_COUNTER := V_COUNTER + 1;
END LOOP;
FOR I IN RESULTS.FIRST .. RESULTS.LAST LOOP
IF I = RESULTS.LAST THEN
DBMS_OUTPUT.PUT_LINE(RESULTS(I).COL_NAME);
ELSIF I = RESULTS.FIRST THEN
DBMS_OUTPUT.PUT(' |'||RESULTS(I).COL_NAME||'|');
ELSE
DBMS_OUTPUT.PUT(RESULTS(I).COL_NAME||'|');
END IF ;
END LOOP;
FOR I IN RESULTS.FIRST .. RESULTS.LAST LOOP
IF I = RESULTS.LAST THEN
DBMS_OUTPUT.PUT_LINE(RESULTS(I).MIN_LENGTH);
ELSIF I = RESULTS.FIRST THEN
DBMS_OUTPUT.PUT('MIN_LENGTH|'||RESULTS(I).MIN_LENGTH||'|');
ELSE
DBMS_OUTPUT.PUT(RESULTS(I).MIN_LENGTH||'|');
END IF ;
END LOOP;
FOR I IN RESULTS.FIRST .. RESULTS.LAST LOOP
IF I = RESULTS.LAST THEN
DBMS_OUTPUT.PUT_LINE(RESULTS(I).MAX_LENGTH);
ELSIF I = RESULTS.FIRST THEN
DBMS_OUTPUT.PUT('MAX_LENGTH|'||RESULTS(I).MAX_LENGTH||'|');
ELSE
DBMS_OUTPUT.PUT(RESULTS(I).MAX_LENGTH||'|');
END IF ;
END LOOP;
end;
The output from the below code is:
|LAT|MISC|SID|NO
MIN_LENGTH|1|2|1|1
MAX_LENGTH|6|6|4|2
The output is as I expect, but is there anyway to loop through the columns using an index (ie. j) instead of doing RESULTS(I).MAX_LENGTH , RESULTS(I).MAX_LENGTH etc ? The concern is that when adding extra columns to the 'R_RESULT_REC' record, another loop is required.
set serveroutput on
DECLARE
TYPE R_RESULT_REC IS RECORD
(COL_NAME VARCHAR2(100),
MIN_LENGTH NUMBER,
MAX_LENGTH NUMBER
);
TYPE tr_RESULT IS TABLE OF R_RESULT_REC;
RESULTS TR_RESULT := TR_RESULT();
v_counter NUMBER := 1;
BEGIN
FOR J IN (SELECT DISTINCT COLUMN_NAME FROM ALL_TAB_COLUMNS
WHERE OWNER = 'SYSTEM'
and TABLE_NAME = 'SPECCHAR')
LOOP
RESULTS.EXTEND;
RESULTS(V_COUNTER).COL_NAME := J.COLUMN_NAME;
EXECUTE IMMEDIATE 'SELECT MIN(LENGTH('||J.COLUMN_NAME||')),
MAX(LENGTH('||J.COLUMN_NAME||'))
FROM '||'SYSTEM'||'.'||'SPECCHAR' INTO
RESULTS(V_COUNTER).MIN_LENGTH,
RESULTS(V_COUNTER).MAX_LENGTH;
V_COUNTER := V_COUNTER + 1;
END LOOP;
FOR I IN RESULTS.FIRST .. RESULTS.LAST LOOP
IF I = RESULTS.LAST THEN
DBMS_OUTPUT.PUT_LINE(RESULTS(I).COL_NAME);
ELSIF I = RESULTS.FIRST THEN
DBMS_OUTPUT.PUT(' |'||RESULTS(I).COL_NAME||'|');
ELSE
DBMS_OUTPUT.PUT(RESULTS(I).COL_NAME||'|');
END IF ;
END LOOP;
FOR I IN RESULTS.FIRST .. RESULTS.LAST LOOP
IF I = RESULTS.LAST THEN
DBMS_OUTPUT.PUT_LINE(RESULTS(I).MIN_LENGTH);
ELSIF I = RESULTS.FIRST THEN
DBMS_OUTPUT.PUT('MIN_LENGTH|'||RESULTS(I).MIN_LENGTH||'|');
ELSE
DBMS_OUTPUT.PUT(RESULTS(I).MIN_LENGTH||'|');
END IF ;
END LOOP;
FOR I IN RESULTS.FIRST .. RESULTS.LAST LOOP
IF I = RESULTS.LAST THEN
DBMS_OUTPUT.PUT_LINE(RESULTS(I).MAX_LENGTH);
ELSIF I = RESULTS.FIRST THEN
DBMS_OUTPUT.PUT('MAX_LENGTH|'||RESULTS(I).MAX_LENGTH||'|');
ELSE
DBMS_OUTPUT.PUT(RESULTS(I).MAX_LENGTH||'|');
END IF ;
END LOOP;
end;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
它使用了 DBMS_SQL,所以读起来相当困难。我看到使用它的主要原因是我可以获得 SQL 语句的列式描述以及基于缓冲区而不是基于对象的获取。
它不是在处理过程中调用 DBMS_OUTPUT,而是构建一个用于输出的记录表,为了简单起见,使用关联数组。
可以进一步细化为每个函数应用一个数组或可解析的函数列表,但这似乎超出了当前的要求。如果添加新的聚合函数,则代码的性质将需要编辑。
调用概述(2c + a + s):
OP的调用概述(c*s + a + 1):
测试数据:
代码:
结果:
This uses DBMS_SQL, so it's pretty snarly to read. The main reason I saw to use it was that I could get columnar descriptions of a SQL statement and to a buffer-based, not object-based fetch.
Rather than making calls to DBMS_OUTPUT during the processing, it builds a table of records for output, using associative arrays for simplicity.
It could further be refined to have an array or parsable list of functions to apply to each function, but that seems excess to current requirements. The nature of the code would require editing if new aggregation functions are being added.
Call overview (2c + a + s):
OP's call overview (c*s + a + 1):
Test data:
Code:
Results:
如果您想使用 DBMS_SQL 包(有时非常复杂),那么 DBMS_SQL.COLUMN_VALUE 函数可能适合您。
更新:
或者更好:DBMS_SQL.DESC_REC
你可以参考:
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_sql.htm#i996963
注意示例 8
我还没有测试过它
更新:
也许您真正想要的是循环对象类型属性而不是表列,所以也许您应该尝试不同的方法:
使您的类型 R_RESULT_REC 成为数据库中的对象类型,然后您可以循环查询结果:
这与使用索引不同,但您仍然不需要对列名称/类型属性进行硬编码,
这里是代码(基于您的):
然后:
如果您向记录添加另一个属性(并使用值启动它),它将自动显示它。
If you want to use the DBMS_SQL package (which is sometimes very complex), then there is a DBMS_SQL.COLUMN_VALUE function that may work for you.
update:
Or even better: DBMS_SQL.DESC_REC
you can refer to:
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_sql.htm#i996963
notice example 8
I haven't tested it
update:
Perhaps what you really want is to loop on an Object type attributes and not a table column, so maybe you should try a different approach:
Make your type R_RESULT_REC an Object type in the DB and then you can loop on the query results:
It's not like working with indexes but you still don't need to hard code the column names / type attributes
here is the code (based on yours):
and then:
If you'll add another attribute to the Record (and initiate it with values) , it will automatic display it.
为此,请利用 Oracle 的统计数据。
首先,使用 dbms_stats.gather_table_stats 在表上完全构建统计信息
然后,创建以下函数来帮助转换 Oracle 存储在 all_tab_columns 中的原始低/高值
然后,只需选择每列的低/高值:
Take advantage of Oracle's stats for this.
First, fully build stats on table using dbms_stats.gather_table_stats
Then, create the following function to help translate the raw low/high values that Oracle stores in all_tab_columns
Then, just select the low/high values for each column: