根据动态信息对嵌套 table 进行排序
Sort Nested table based on dynamic information
我无法根据按子句排序的一些动态信息对嵌套 table 进行排序。
这里唯一的区别是我需要在order by子句中动态定义列和方向
SELECT CAST(MULTISET(SELECT *
FROM TABLE(table_a)
ORDER BY P_SORT_COLUMN P_DIRECTION
) as table_typ)
INTO table_b
FROM dual;
所以为了解决问题,我想到了使用动态 SQL 并将其放入 proc 中,因为表单无法动态执行此操作
loc_sql_stmt VARCHAR2(500);
BEGIN
loc_sql_stmt := 'SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE(P_TABLE_A) ' ||
'ORDER BY P_COLUMN P_DIRECTION || ) as table_typ) ' ||
'INTO P_TABLE_B' ||
'FROM dual;';
EXECUTE IMMEDIATE loc_sql_stmt
USING IN P_TABLE_A, P_COLUMN, P_DIRECTION, P_TABLE_B;
END;
我从 EXECUTE IMMEDIATE 行得到的错误是“ORA-00936 缺少表达式
那么有没有更好的方法来按任何给定的列和方向对嵌套 table 进行排序,或者我如何使这个动态 SQL 起作用?
这是一个示例:
在数据库中创建:
CREATE OR REPLACE TYPE table_obj AS OBJECT(
column1 VARCHAR2(20),
column2 VARCHAR2(20));
CREATE OR REPLACE TYPE table_typ AS TABLE OF table_obj;
然后是样本 运行:
DECLARE
table_a table_typ := table_typ ();
table_b table_typ := table_typ ();
loc_idx NUMBER;
loc_sort_column INTEGER := 1;
loc_desc VARCHAR2 (4);
P_SORT_COLUMN VARCHAR2 (100) := 'column1';
P_DIRECTION VARCHAR2 (4) := 'DESC';
loc_sql_stmt VARCHAR2 (500);
BEGIN
FOR i IN 1 .. 5
LOOP
loc_idx := table_a.COUNT + 1;
table_a.EXTEND;
table_a (loc_idx) := table_obj (NULL, NULL);
table_a (loc_idx).column1 := TO_CHAR (loc_idx);
table_a (loc_idx).column2 := TO_CHAR (loc_idx);
END LOOP;
--
loc_sql_stmt :=
'SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE(' || table_a || ') ' ||
'ORDER BY ' || P_SORT_COLUMN || ' '|| P_DIRECTION ||
' ) as table_typ) ' ||
'INTO :table_b' ||
'FROM dual';
EXECUTE IMMEDIATE loc_sql_stmt USING IN OUT table_a, table_b;
FOR i IN 1 .. table_b.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE (table_b (i).rx_number);
END LOOP;
END;
如果您的 column/direction 选择有限,请尝试在订单中使用 case 语句,简单示例:
select * from tab
order by case when :order = 'c1_asc' then c1 else null end asc
, case when :order = 'c1_desc' then c1 else null end desc
, case when :order = 'c2_asc' then c2 else null end asc
, case when :order = 'c2_desc' then c2 else null end desc
/* ... */
;
要将变量传递给原生动态 SQL 在参数名称前使用 :
,构建动态语句使用连接,就像这样
loc_sql_stmt VARCHAR2(500);
BEGIN
loc_sql_stmt := 'SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE('|| P_TABLE_A || ') ' ||
'ORDER BY ' || P_COLUMN || ', ' || P_DIRECTION || ' ) as table_typ) ' ||
'INTO :P_TABLE_B' ||
'FROM dual;';
EXECUTE IMMEDIATE loc_sql_stmt
USING OUT P_TABLE_B;
END;
编辑版本:
现在看到你的代码,我明白你需要什么了。为了让它工作我们需要使用动态 PL/SQL 块,而不是本地 SQL 这里是你的示例的工作代码,并注意什么是变量和什么是连接文字
DECLARE
table_a table_typ := table_typ();
table_b table_typ := table_typ();
loc_idx NUMBER;
loc_sort_column INTEGER := 1;
loc_desc VARCHAR2(4);
P_SORT_COLUMN VARCHAR2(100) := 'column1';
P_DIRECTION VARCHAR2(4) := 'desc';
loc_sql_stmt VARCHAR2(500);
BEGIN
FOR i IN 1 .. 5
LOOP
loc_idx := table_a.COUNT + 1;
table_a.EXTEND;
table_a(loc_idx) := table_obj(NULL, NULL);
table_a(loc_idx).column1 := TO_CHAR(loc_idx);
table_a(loc_idx).column2 := TO_CHAR(loc_idx);
END LOOP;
--
loc_sql_stmt := 'begin SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE(:table_a ) ORDER BY ' || P_SORT_COLUMN || ' ' ||
P_DIRECTION || ' ) as table_typ ) ' || ' INTO :table_b ' ||
'FROM dual; end;';
EXECUTE IMMEDIATE loc_sql_stmt
USING table_a, IN OUT table_b;
FOR i IN 1 .. table_b.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(table_b(i).column1);
END LOOP;
END;
我无法根据按子句排序的一些动态信息对嵌套 table 进行排序。
这里唯一的区别是我需要在order by子句中动态定义列和方向
SELECT CAST(MULTISET(SELECT *
FROM TABLE(table_a)
ORDER BY P_SORT_COLUMN P_DIRECTION
) as table_typ)
INTO table_b
FROM dual;
所以为了解决问题,我想到了使用动态 SQL 并将其放入 proc 中,因为表单无法动态执行此操作
loc_sql_stmt VARCHAR2(500);
BEGIN
loc_sql_stmt := 'SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE(P_TABLE_A) ' ||
'ORDER BY P_COLUMN P_DIRECTION || ) as table_typ) ' ||
'INTO P_TABLE_B' ||
'FROM dual;';
EXECUTE IMMEDIATE loc_sql_stmt
USING IN P_TABLE_A, P_COLUMN, P_DIRECTION, P_TABLE_B;
END;
我从 EXECUTE IMMEDIATE 行得到的错误是“ORA-00936 缺少表达式
那么有没有更好的方法来按任何给定的列和方向对嵌套 table 进行排序,或者我如何使这个动态 SQL 起作用?
这是一个示例:
在数据库中创建:
CREATE OR REPLACE TYPE table_obj AS OBJECT(
column1 VARCHAR2(20),
column2 VARCHAR2(20));
CREATE OR REPLACE TYPE table_typ AS TABLE OF table_obj;
然后是样本 运行:
DECLARE
table_a table_typ := table_typ ();
table_b table_typ := table_typ ();
loc_idx NUMBER;
loc_sort_column INTEGER := 1;
loc_desc VARCHAR2 (4);
P_SORT_COLUMN VARCHAR2 (100) := 'column1';
P_DIRECTION VARCHAR2 (4) := 'DESC';
loc_sql_stmt VARCHAR2 (500);
BEGIN
FOR i IN 1 .. 5
LOOP
loc_idx := table_a.COUNT + 1;
table_a.EXTEND;
table_a (loc_idx) := table_obj (NULL, NULL);
table_a (loc_idx).column1 := TO_CHAR (loc_idx);
table_a (loc_idx).column2 := TO_CHAR (loc_idx);
END LOOP;
--
loc_sql_stmt :=
'SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE(' || table_a || ') ' ||
'ORDER BY ' || P_SORT_COLUMN || ' '|| P_DIRECTION ||
' ) as table_typ) ' ||
'INTO :table_b' ||
'FROM dual';
EXECUTE IMMEDIATE loc_sql_stmt USING IN OUT table_a, table_b;
FOR i IN 1 .. table_b.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE (table_b (i).rx_number);
END LOOP;
END;
如果您的 column/direction 选择有限,请尝试在订单中使用 case 语句,简单示例:
select * from tab
order by case when :order = 'c1_asc' then c1 else null end asc
, case when :order = 'c1_desc' then c1 else null end desc
, case when :order = 'c2_asc' then c2 else null end asc
, case when :order = 'c2_desc' then c2 else null end desc
/* ... */
;
要将变量传递给原生动态 SQL 在参数名称前使用 :
,构建动态语句使用连接,就像这样
loc_sql_stmt VARCHAR2(500);
BEGIN
loc_sql_stmt := 'SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE('|| P_TABLE_A || ') ' ||
'ORDER BY ' || P_COLUMN || ', ' || P_DIRECTION || ' ) as table_typ) ' ||
'INTO :P_TABLE_B' ||
'FROM dual;';
EXECUTE IMMEDIATE loc_sql_stmt
USING OUT P_TABLE_B;
END;
编辑版本:
现在看到你的代码,我明白你需要什么了。为了让它工作我们需要使用动态 PL/SQL 块,而不是本地 SQL 这里是你的示例的工作代码,并注意什么是变量和什么是连接文字
DECLARE
table_a table_typ := table_typ();
table_b table_typ := table_typ();
loc_idx NUMBER;
loc_sort_column INTEGER := 1;
loc_desc VARCHAR2(4);
P_SORT_COLUMN VARCHAR2(100) := 'column1';
P_DIRECTION VARCHAR2(4) := 'desc';
loc_sql_stmt VARCHAR2(500);
BEGIN
FOR i IN 1 .. 5
LOOP
loc_idx := table_a.COUNT + 1;
table_a.EXTEND;
table_a(loc_idx) := table_obj(NULL, NULL);
table_a(loc_idx).column1 := TO_CHAR(loc_idx);
table_a(loc_idx).column2 := TO_CHAR(loc_idx);
END LOOP;
--
loc_sql_stmt := 'begin SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE(:table_a ) ORDER BY ' || P_SORT_COLUMN || ' ' ||
P_DIRECTION || ' ) as table_typ ) ' || ' INTO :table_b ' ||
'FROM dual; end;';
EXECUTE IMMEDIATE loc_sql_stmt
USING table_a, IN OUT table_b;
FOR i IN 1 .. table_b.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(table_b(i).column1);
END LOOP;
END;