Cur*_* F. 5 sql oracle oracle11gr2
我正在使用两个实体:Item和Attribute看起来如下所示:
Item
----
itemId
Attribute
---------
attributeId
name
Run Code Online (Sandbox Code Playgroud)
一个Item具有Attributes,如在关联表中指定:
ItemAttribute
--------------
itemId
attributeId
Run Code Online (Sandbox Code Playgroud)
当这些数据到达客户端时,它将显示Item每行一行,每行将按Attribute名称列出s.例如:
Item Attributes
---- ----------
1 A, B, C
2 A, C
3 A, B
Run Code Online (Sandbox Code Playgroud)
用户可以选择对Attributes列进行排序,因此我们需要能够按如下方式对数据进行排序:
Item Attributes
---- ----------
3 A, B
1 A, B, C
2 A, C
Run Code Online (Sandbox Code Playgroud)
目前,我们每ItemAttribute行获得一行数据.基本上:
SELECT Item.itemId,
Attribute.name
FROM Item
JOIN ItemAttribute
ON ItemAttribute.itemId = Item.itemId
JOIN Attribute
ON Attribute.attributeId = ItemAttribute.attributeId
ORDER BY Item.itemId;
Run Code Online (Sandbox Code Playgroud)
产生如下结果:
itemId name
------ ----
1 A
1 B
1 C
2 A
2 C
3 A
3 B
Run Code Online (Sandbox Code Playgroud)
实际ORDER BY条款基于用户输入.它通常是一个列,因此排序很简单,处理结果集的app端循环将Attribute名称组合成逗号分隔列表,以便在客户端上显示.但是当用户要求对该列表进行排序时,让Oracle对结果进行排序以便 - 使用上面的示例 - 我们得到:
itemId name
------ ----
3 A
3 B
1 A
1 B
1 C
2 A
2 C
Run Code Online (Sandbox Code Playgroud)
Oracle的LISTAGG功能可用于在排序之前生成属性列表; 但是Attribute.name可以是一个非常长的字符串,并且组合列表可能大于4000个字符,这将导致查询失败.
有没有一种干净,有效的方法使用Oracle SQL(11gR2)以这种方式对数据进行排序?
这里确实有两个问题:
聚合如此多的数据并将其显示在单列中是否明智?
无论如何,您将需要某种大型结构来显示超过 4000 个字符,例如 a CLOB。您可以按照Tom Kyte 的线程之一中描述的一般准则编写自己的聚合方法(显然您需要对其进行修改,以便最终输出是 CLOB)。
我将演示一个更简单的方法,使用嵌套表和自定义函数(适用于 10g):
SQL> CREATE TYPE tab_varchar2 AS TABLE OF VARCHAR2(4000);
2 /
Type created.
SQL> CREATE OR REPLACE FUNCTION concat_array(p tab_varchar2) RETURN CLOB IS
2 l_result CLOB;
3 BEGIN
4 FOR cc IN (SELECT column_value FROM TABLE(p) ORDER BY column_value) LOOP
5 l_result := l_result ||' '|| cc.column_value;
6 END LOOP;
7 return l_result;
8 END;
9 /
Function created.
SQL> SELECT item,
2 concat_array(CAST (collect(attribute) AS tab_varchar2)) attributes
3 FROM data
4 GROUP BY item;
ITEM ATTRIBUTES
1 a b c
2 a c
3 a b
Run Code Online (Sandbox Code Playgroud)
不幸的是,您无法在 Oracle 中按任意大的列进行排序:存在与排序键的类型和长度相关的已知限制。
ORA-00932:不一致的数据类型:预期 - 得到 CLOB。ORA-06502:PL/SQL:数字或值错误:字符串缓冲区太小我建议您按属性列的前 4000 个字节排序:
SQL> SELECT * FROM (
2 SELECT item,
3 concat_array(CAST (collect(attribute) AS tab_varchar2)) attributes
4 FROM data
5 GROUP BY item
6 ) order by dbms_lob.substr(attributes, 4000, 1);
ITEM ATTRIBUTES
3 a b
1 a b c
2 a c
Run Code Online (Sandbox Code Playgroud)