![](/img/trans.png)
[英]How to get column names of a hypothetical table returned by a query oracle sql
[英]Get column names of the result of a query Oracle SQL
我需要一个查询来获取另一个查询结果的列名。 另一个查询可以是任何东西——我不能对它做任何假设,但它通常是一些SELECT
语句。
例如,如果我有这个表Members
Id | Name | Age
---|------|----
1 | John | 25
2 | Amir | 13
而这个SELECT
语句SELECT Name, Age FROM Members
然后我尝试编写的查询结果将是
Name
Age
在 SQL Server 中,有一个函数 - sys.dm_exec_describe_first_result_set
- 可以执行此操作,但我在 Oracle 中找不到等效函数。
我尝试使用此答案,但由于权限问题,我无法使用CREATE TYPE
语句,并且出于同样的原因,我可能无法使用CREATE FUNCTION
语句。
假设你有一个这样的查询:
select *
from (select deptno, job, sal from scott.emp)
pivot (avg(sal) as avg_sal for job in
('ANALYST' as analyst, 'CLERK' as clerk, 'SALESMAN' as salesman)
)
order by deptno
;
这产生了结果:
DEPTNO ANALYST_AVG_SAL CLERK_AVG_SAL SALESMAN_AVG_SAL
---------- --------------- ------------- ----------------
10 1300
20 3000 950
30 950 1400
注意列名(如ANALYST_AVG_SAL
)——它们在查询中的任何地方都没有完全以这种形式出现! 它们由两个独立的部分组成,并用下划线组合在一起。
现在,如果您被允许创建视图(请注意,这不会在您的数据库中创建任何数据——它只是保存查询的文本),您可以这样做:
创建视图(只需将第一行代码添加到我们已有的内容中):
create view q201028_vw as
select *
from (select deptno, job, sal from scott.emp)
pivot (avg(sal) as avg_sal for job in
('ANALYST' as analyst, 'CLERK' as clerk, 'SALESMAN' as salesman)
)
order by deptno
;
(这里我假设您有某种方法来识别查询,一个 id 像Q201028
,并在视图名称中使用它。这并不重要,除非您需要经常这样做并且同时进行大量查询。 )
然后您可以通过查询*_TAB_COLUMNS
找到列名(以及它们的顺序,以及 - 如果需要 - 它们的数据类型等)。 例如:
select column_id, column_name
from user_tab_columns
where table_name = 'Q201028_VW'
order by column_id
;
COLUMN_ID COLUMN_NAME
---------- --------------------
1 DEPTNO
2 ANALYST_AVG_SAL
3 CLERK_AVG_SAL
4 SALESMAN_AVG_SAL
现在,如果您不需要其他任何东西,您可以删除该视图。
顺便说一句:在 Oracle 中,在数据库中“保存”查询的“通常”方法是创建视图。 如果它们已经存在于您的数据库中,那么您所需要的就是我向您展示的最后一步。 否则,首先是“其他查询”(您需要为其查找列)吗?
我将使用 dbms_sql 包,以下代码示例应向您展示如何开始:
DECLARE
cursorID INTEGER;
status INTEGER;
colCount INTEGER;
rowCount INTEGER;
description dbms_sql.desc_tab;
colType INTEGER;
stringValue VARCHAR2(32676);
sqlCmd VARCHAR2(32767);
BEGIN
-- open cursor
cursorID := dbms_sql.open_cursor;
-- parse statement
dbms_sql.parse(cursorID, 'select * from user_tables', dbms_sql.native);
-- describe columns
dbms_sql.describe_columns(cursorID, colCount, description);
-- cursor close
dbms_sql.close_cursor(cursorID);
-- open cursor
cursorID := dbms_sql.open_cursor;
-- assemble a new select only using up to 5 the "text" columns
FOR i IN 1 .. description.COUNT LOOP
IF (i > 5) THEN
EXIT;
END IF;
IF (description(i).col_type IN (1, 112)) THEN
IF (sqlCmd IS NOT NULL) THEN
sqlCmd := sqlCmd || ', ';
END IF;
sqlCmd := sqlCmd || description(i).col_name;
END IF;
END LOOP;
sqlCmd := 'SELECT ' || sqlCmd || ' FROM user_tables';
dbms_output.put_line(sqlCmd);
-- parse statement
dbms_sql.parse(cursorID, sqlCmd, dbms_sql.native);
-- describe columns
dbms_sql.describe_columns(cursorID, colCount, description);
-- define columns
FOR i IN 1 .. description.COUNT LOOP
dbms_sql.define_column(cursorID, i, stringValue, 4000);
END LOOP;
-- execute
status := dbms_sql.execute(cursorID);
-- fetch up to 5 rows
rowCount := 0;
WHILE (dbms_sql.fetch_rows(cursorID) > 0) LOOP
rowCount := rowCount + 1;
IF (rowCount > 5) THEN
EXIT;
END IF;
dbms_output.put_line('row # ' || rowCount);
FOR i IN 1 .. description.COUNT LOOP
dbms_sql.column_value(cursorID, i, stringValue);
dbms_output.put_line('column "' || description(i).col_name || '" = "' || stringValue || '"');
END LOOP;
END LOOP;
-- cursor close
dbms_sql.close_cursor(cursorID);
END;
/
正如 astentx 所建议的,您可以使用公共表表达式函数将 PL/SQL 代码打包成 SQL 语句。 该解决方案只是一条 SQL 语句,不需要非默认权限,也不会创建任何永久对象。
(唯一的缺点是并非所有 SQL 工具都能理解这些类型的 WITH 子句,并且它们可能会抛出错误,期望使用不同的语句终止符。)
SQL> create table members(id number, name varchar2(100), age number);
Table created.
SQL> with function get_result_column_names(p_sql varchar2) return sys.odcivarchar2list is
2 v_cursor_id integer;
3 v_col_cnt integer;
4 v_columns dbms_sql.desc_tab;
5 v_column_names sys.odcivarchar2list := sys.odcivarchar2list();
6 begin
7 v_cursor_id := dbms_sql.open_cursor;
8 dbms_sql.parse(v_cursor_id, p_sql, dbms_sql.native);
9 dbms_sql.describe_columns(v_cursor_id, v_col_cnt, v_columns);
10
11 for i in 1 .. v_columns.count loop
12 v_column_names.extend;
13 v_column_names(v_column_names.count) := v_columns(i).col_name;
14 end loop;
15
16 dbms_sql.close_cursor(v_cursor_id);
17
18 return v_column_names;
19 exception when others then
20 dbms_sql.close_cursor(v_cursor_id);
21 raise;
22 end;
23 select *
24 from table(get_result_column_names(q'[select name, age from members]'));
25 /
COLUMN_VALUE
--------------------------------------------------------------------------------
NAME
AGE
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.