在 Oracle(11.2 之前)中:使用 cast(collect(...)) 时,如何对结果进行排序?
Posted
技术标签:
【中文标题】在 Oracle(11.2 之前)中:使用 cast(collect(...)) 时,如何对结果进行排序?【英文标题】:In Oracle (pre-11.2): When using cast(collect(...)), how do I order the result? 【发布时间】:2010-12-10 10:25:58 【问题描述】:当使用 cast(collect(...)) 时,如何排序结果?
我有一个名为 GetStringForTable 的函数,定义如下:
FUNCTION GetStringForTable(vTable in TVarCharTable, vDelimeter in varchar default ',') return VarChar2 is
aResult varchar2(32767);
i int;
begin
if vTable.count = 0 then
return '';
end if;
for i in 1 .. vTable.Count loop
if i > 1 then
aResult := aResult || vDelimeter;
end if;
aResult := aResult || vTable(i);
end loop;
return aResult;
end GetStringForTable;
我是这样使用它的:
select
name,
rep.GetStringForTable
((
Select
cast(collect(name) as TVarCharTable)
from
contacts
where
debtoraccount = dt.accountnumber
)
,', ' --Delimiter
) "Contacts"
from debtable dt
where name like '%Svein%';
问题是结果没有排序。当我想要“爱丽丝,鲍勃,卡罗尔,戴夫”时,我会得到“戴夫,鲍勃,卡罗尔,爱丽丝”。我如何订购结果?如果尝试以下方法,但均无效:
select
name,
rep.GetStringForTable
((
Select
cast(collect(name) as TVarCharTable)
from
contacts
where
debtoraccount = dt.accountnumber
order by name <= ORA-00907: missing right parenthesis
)
,', ' --Skilletegn
) "Contacts"
from debtable dt
where name like '%Svein%';
和
select
name,
rep.GetStringForTable
((
select * from
(
Select
cast(collect(name) as TVarCharTable)
from
contacts
where
debtoraccount = dt.accountnumber <= ORA-00904: string: invalid identifier
order by name
)
)
,', ' --Skilletegn
) "Contacts"
from debtable dt
where name like '%Svein%';
理想情况下,我想在不更改 GetStringForTable 函数的情况下进行排序。
谁能帮忙?
【问题讨论】:
您能否将您的 Oracle 版本号添加到问题中? 我们的 SW 有几个可以运行,但目前还没有 11.2。我们的系统要求将从 01.01.11 更改为 Oracle 11.2,这将使此类事情变得更容易。 【参考方案1】: cast(collect(name order by name) as TVarCharTable)
此语法在11gR1 manual 中首次提及。但它似乎可以在 10g 上正常工作,即使它不是 documented。
【讨论】:
【参考方案2】:一种方法是修改 GetStringForTable 以使输出有序(您可以有两个函数:一个是有序的,另一个不是)
SQL> CREATE OR REPLACE TYPE TVarCharTable AS TABLE OF VARCHAR2(30);
2 /
Type created
SQL> CREATE OR REPLACE FUNCTION GetStringForTable(
2 vTable IN TVarCharTable,
3 vDelimeter IN VARCHAR DEFAULT ','
4 ) RETURN VARCHAR2 IS
5 aResult VARCHAR2(32767);
6 i INT := 1;
7 BEGIN
8 IF vTable.COUNT = 0 THEN
9 RETURN '';
10 END IF;
11 FOR cc IN (SELECT COLUMN_VALUE cv
12 FROM TABLE(CAST(vtable AS TVarCharTable))
13 ORDER BY COLUMN_VALUE) LOOP
14 IF i > 1 THEN
15 aResult := aResult || vDelimeter;
16 END IF;
17 aResult := aResult || cc.cv;
18 i := i+1;
19 END LOOP;
20 RETURN aResult;
21 END GetStringForTable;
22 /
Function created
SQL> SELECT GetStringForTable(TVarCharTable('B', 'A', 'D', 'C')) FROM dual;
GETSTRINGFORTABLE(TVARCHARTABL
---------------------------------------------------------------------
A,B,C,D
更新
我找到了一种解决方法,但不幸的是,在额外的测试中,不能保证 ORDER。它将取决于选择的访问路径。不过,它可能适用于您的情况:
SQL> SELECT dNAME,
2 GetStringForTable((SELECT CAST(COLLECT(eNAME) AS TVarCharTable)
3 FROM (SELECT *
4 FROM scott.emp
5 ORDER BY ename) e
6 /* ^^^^^^^^ */
7 WHERE e.deptno = dt.deptno),
8 ', ' --Delimiter
9 ) "Contacts"
10 FROM scott.dept dt;
DNAME Contacts
-------------- ----------------------------------------------------
ACCOUNTING CLARK, KING, MILLER
RESEARCH ADAMS, FORD, JONES, SCOTT, SMITH
SALES ALLEN, BLAKE, JAMES, MARTIN, TURNER, WARD
OPERATIONS
您可以通过一种技巧来强制 ORDER 实现子查询,但这会阻止优化器使用大多数有效路径,例如:
SQL> WITH employee AS (
2 SELECT *
3 FROM scott.emp
4 WHERE ROWNUM > 0 /* will materialize the subquery */
5 ORDER BY ename
6 )
7 SELECT dNAME,
8 GetStringForTable((SELECT CAST(COLLECT(eNAME) AS TVarCharTable)
9 FROM employee e
10 WHERE e.deptno = dt.deptno),
11 ', ' --Delimiter
12 ) "Contacts"
13 FROM scott.dept dt;
DNAME Contacts
-------------- -----------------------------------------------------
ACCOUNTING CLARK, KING, MILLER
RESEARCH ADAMS, FORD, JONES, SCOTT, SMITH
SALES ALLEN, BLAKE, JAMES, MARTIN, TURNER, WARD
OPERATIONS
【讨论】:
是的,这可行,但我希望有一个不改变功能的解决方案。如果我们更改功能,我们将不得不为所有客户复制该更改,这可能会出现问题。您认为可以采取其他方式吗? 此外,排序可能因实例而异,不一定按字母顺序排列。对于一份报告,客户可能想要“Alice (237)、Bob (695)、Carol (107)、Dave (471)”,但对于另一份报告,他们可能想要“Bob (695)、Dave (471)、Alice ( 237),卡罗尔(107)” @Svein:根据您的设置,您可能会发现子查询中的内部 ORDER BY 将保留在外部子查询中。请参阅我更新的示例。以上是关于在 Oracle(11.2 之前)中:使用 cast(collect(...)) 时,如何对结果进行排序?的主要内容,如果未能解决你的问题,请参考以下文章
ResultSet.next() 在使用 jdbc 与 oracle 11.2 交谈时挂起