Sql 系统通过CLOB的路径连接

Sql 系统通过CLOB的路径连接,sql,oracle,oracle11g,string-aggregation,Sql,Oracle,Oracle11g,String Aggregation,我有一个ORA-01489:字符串连接的结果太长错误在Oracle Database 11g Enterprise Edition 11.2.0.4.0-64位生产、PL/SQL 11.2.0.4.0-生产、CORE 11.2.0.4.0生产、TNS for Linux:11.2.0.4.0-生产、NLSRTL 11.2.0.4.0-生产上执行此查询: SELECT "USER_PRIMARY_UNIT","LOGIN","FIRST_NAME","LAST_NAME","UNIT_ROLE"

我有一个ORA-01489:字符串连接的结果太长错误在Oracle Database 11g Enterprise Edition 11.2.0.4.0-64位生产、PL/SQL 11.2.0.4.0-生产、CORE 11.2.0.4.0生产、TNS for Linux:11.2.0.4.0-生产、NLSRTL 11.2.0.4.0-生产上执行此查询:

SELECT "USER_PRIMARY_UNIT","LOGIN","FIRST_NAME","LAST_NAME","UNIT_ROLE"
FROM (
SELECT user_primary_unit,login, first_name,  last_name,
       LTRIM(MAX(SYS_CONNECT_BY_PATH(rights,' / '))
       KEEP (DENSE_RANK LAST ORDER BY curr),' / ') AS UNIT_ROLE
      FROM  
        (SELECT  login,
              first_name,  
              last_name,
              user_primary_unit,
              rights,
              ROW_NUMBER() OVER (PARTITION BY login ORDER BY rights) AS curr,
              ROW_NUMBER() OVER (PARTITION BY login ORDER BY rights) -1 AS prev
        FROM  (select   member0_.login,  member0_.first_name first_name, unit2.unit_name user_primary_unit,  member0_.last_name last_name,
                        CONCAT(CONCAT(unit.unit_name, ' - '), role3_.role_name) rights 
 from
  IOT_DEVICES.t_member member0_
 inner join  IOT_DEVICES.t_user member0_1_    on member0_.member_id=member0_1_.user_id
 inner join  IOT_DEVICES.t_playable_role playedrole1_    on member0_.member_id=playedrole1_.user_id
 inner join  IOT_DEVICES.t_unit_role unitrole2_    on playedrole1_.unit_role_id=unitrole2_.unit_role_id
 inner join  IOT_DEVICES.t_role role3_    on unitrole2_.role_id=role3_.role_id
 inner join  IOT_DEVICES.t_unit unit    on unitrole2_.unit_id=unit.unit_id
 inner join  IOT_DEVICES.t_unit unit2    on unit2.unit_id=member0_1_.primary_unit_id
 where    current_date between playedrole1_.start_date and playedrole1_.end_date
 order by unit.unit_name
  ))
GROUP BY login, first_name,  last_name, user_primary_unit
CONNECT BY prev = PRIOR curr AND login = PRIOR login
START WITH curr = 1
)
ORDER BY user_PRIMARY_UNIT, FIRST_NAME, LAST_NAME;
此查询的问题在于使用CONCAT运算符| |。Concat运算符返回与char2连接的char1。返回的字符串与char1位于同一字符集中。所以这里concat操作符试图返回varchar2,它有4000个字符的限制,并且正在被超过。当我们尝试用CLOB连接VARCHAR2时,这个问题也可能出现。因此,这里我只想将它的第一个字符串转换为CLOB并避免这个错误。将第一个字符串转换为CLOB后,CONCAT运算符将返回CLOB类型的字符串

因此,我添加了TO_CLOB来转换类型,但随后出现了下一个错误:

ORA-00932:不一致的数据类型:应为-已获取CLOB

我还尝试使用这里定义的包层次结构,但是我得到了一个ORA-00932:不一致的数据类型:预期-获得CLOB

然后我也尝试使用sys.stragg,但是我得到了一个ORA-00978:嵌套的组函数,没有GROUPBY

您可以构建层次结构CLOB路径,这样可能会运行得非常慢。考虑有两个路径列-一个用于VARCHAR2结果,一个用于CURB。构建varchar2直到大小允许,并在CLOB路径中保持NULL,并在varchar2容量不足时切换到CLOB。但这是一个不同的问题

with
base as (
select
    level as id,
    case when level > 1 then level - 1 end as parent_id,
    dbms_random.string('X', 2000) as val
from dual
connect by level <= 50
),
hier(id, parent_id, val, path) as (
    select
        b.id,
        b.parent_id,
        b.val,
        to_clob(concat('/', b.val)) as path
    from base b
    where b.parent_id is null
    union all
    select
        b.id,
        b.parent_id,
        b.val,
        concat(h.path, to_clob(' / '||b.val) )
    from base b
        join hier h on h.id = b.parent_id

)
select rownum, length(h.path)
from hier h;

ROWNUM  LENGTH(H.PATH)
1   2001
2   4004
3   6007
4   8010
5   10013
6   12016
7   14019
8   16022
9   18025
10  20028
11  22031
12  24034
13  26037
14  28040
15  30043
16  32046
17  34049
18  36052
19  38055
20  40058
21  42061
22  44064
23  46067
24  48070
25  50073
26  52076
27  54079
28  56082
29  58085
30  60088
31  62091
32  64094
33  66097
34  68100
35  70103
36  72106
37  74109
38  76112
39  78115
40  80118
41  82121
42  84124
43  86127
44  88130
45  90133
46  92136
47  94139
48  96142
49  98145
50  100148

您可能会找到此页面,因为您正在尝试聚合长度超过4000个字符且已记住的字符串

如果是这样的话,我根据@B Samedi的答案创建了一个小示例,以帮助您解决无法使用的问题


SYS\ U CONNECT\ U BY\ U PATH接受作为输入char/varchar数据类型,CLOB不是。请看这里,因为它似乎与您的问题相同。基本想法是添加另一层包装,在其中可以将短字符串连接到clobAnd。另一个想法是使用STRAGG而不是sys_connect_by_path:另外两个链接可能需要使用更明确的方式逐步通过视图。这将允许您以不同的方式构造数据,并通过将部分数据具体化来加快查询速度。考虑使用WITH子句,并通过实现分层构造结果集的目的。这是一种编写嵌套查询的强大方法。此外,上面的建议在结尾正确之前省略clob元素,否则将不必要地填充内存。使用关键元素构建层次结构,如果需要,在视图中引入主键,以便可以返回并引用排序数据中的CLOB。希望这有帮助
SELECT "USER_PRIMARY_UNIT","LOGIN","FIRST_NAME","LAST_NAME","UNIT_ROLE"
FROM (
SELECT user_primary_unit,login, first_name,  last_name,
       LTRIM(MAX(hierarchy.branch(level,rights,' / '))
       KEEP (DENSE_RANK LAST ORDER BY curr),' / ') AS UNIT_ROLE
      FROM  
        (SELECT  login,
              first_name,  
              last_name,
              user_primary_unit,
              rights,
              ROW_NUMBER() OVER (PARTITION BY login ORDER BY rights) AS curr,
              ROW_NUMBER() OVER (PARTITION BY login ORDER BY rights) -1 AS prev
        FROM  (select   member0_.login,  member0_.first_name first_name, unit2.unit_name user_primary_unit,  member0_.last_name last_name,
                        TO_CLOB(CONCAT(CONCAT(unit.unit_name, ' - '), role3_.role_name)) rights 
 from
  IOT_DEVICES.t_member member0_
 inner join  IOT_DEVICES.t_user member0_1_    on member0_.member_id=member0_1_.user_id
 inner join  IOT_DEVICES.t_playable_role playedrole1_    on member0_.member_id=playedrole1_.user_id
 inner join  IOT_DEVICES.t_unit_role unitrole2_    on playedrole1_.unit_role_id=unitrole2_.unit_role_id
 inner join  IOT_DEVICES.t_role role3_    on unitrole2_.role_id=role3_.role_id
 inner join  IOT_DEVICES.t_unit unit    on unitrole2_.unit_id=unit.unit_id
 inner join  IOT_DEVICES.t_unit unit2    on unit2.unit_id=member0_1_.primary_unit_id
 where    current_date between playedrole1_.start_date and playedrole1_.end_date
 order by unit.unit_name
  ))
GROUP BY login, first_name,  last_name, user_primary_unit
CONNECT BY prev = PRIOR curr AND login = PRIOR login
START WITH curr = 1
)
ORDER BY user_PRIMARY_UNIT, FIRST_NAME, LAST_NAME;
SELECT "USER_PRIMARY_UNIT","LOGIN","FIRST_NAME","LAST_NAME","UNIT_ROLE"
FROM (
SELECT user_primary_unit,login, first_name,  last_name,
       LTRIM(MAX(SYS_CONNECT_BY_PATH(rights,' / '))
       KEEP (DENSE_RANK LAST ORDER BY curr),' / ') AS UNIT_ROLE
      FROM  
        (SELECT  login,
              first_name,  
              last_name,
              user_primary_unit,
              rights,
              ROW_NUMBER() OVER (PARTITION BY login ORDER BY rights) AS curr,
              ROW_NUMBER() OVER (PARTITION BY login ORDER BY rights) -1 AS prev
        FROM  (select   member0_.login,  member0_.first_name first_name, unit2.unit_name user_primary_unit,  member0_.last_name last_name,
                        sys.stragg(sys.stragg(unit.unit_name || ' - ' || role3_.role_name)) rights 
 from
  IOT_DEVICES.t_member member0_
 inner join  IOT_DEVICES.t_user member0_1_    on member0_.member_id=member0_1_.user_id
 inner join  IOT_DEVICES.t_playable_role playedrole1_    on member0_.member_id=playedrole1_.user_id
 inner join  IOT_DEVICES.t_unit_role unitrole2_    on playedrole1_.unit_role_id=unitrole2_.unit_role_id
 inner join  IOT_DEVICES.t_role role3_    on unitrole2_.role_id=role3_.role_id
 inner join  IOT_DEVICES.t_unit unit    on unitrole2_.unit_id=unit.unit_id
 inner join  IOT_DEVICES.t_unit unit2    on unit2.unit_id=member0_1_.primary_unit_id
 where    current_date between playedrole1_.start_date and playedrole1_.end_date
 order by unit.unit_name
  ))
GROUP BY login, first_name,  last_name, user_primary_unit
CONNECT BY prev = PRIOR curr AND login = PRIOR login
START WITH curr = 1
)
ORDER BY user_PRIMARY_UNIT, FIRST_NAME, LAST_NAME;
with
base as (
select
    level as id,
    case when level > 1 then level - 1 end as parent_id,
    dbms_random.string('X', 2000) as val
from dual
connect by level <= 50
),
hier(id, parent_id, val, path) as (
    select
        b.id,
        b.parent_id,
        b.val,
        to_clob(concat('/', b.val)) as path
    from base b
    where b.parent_id is null
    union all
    select
        b.id,
        b.parent_id,
        b.val,
        concat(h.path, to_clob(' / '||b.val) )
    from base b
        join hier h on h.id = b.parent_id

)
select rownum, length(h.path)
from hier h;

ROWNUM  LENGTH(H.PATH)
1   2001
2   4004
3   6007
4   8010
5   10013
6   12016
7   14019
8   16022
9   18025
10  20028
11  22031
12  24034
13  26037
14  28040
15  30043
16  32046
17  34049
18  36052
19  38055
20  40058
21  42061
22  44064
23  46067
24  48070
25  50073
26  52076
27  54079
28  56082
29  58085
30  60088
31  62091
32  64094
33  66097
34  68100
35  70103
36  72106
37  74109
38  76112
39  78115
40  80118
41  82121
42  84124
43  86127
44  88130
45  90133
46  92136
47  94139
48  96142
49  98145
50  100148
with dummy_text as (
select 'teststring ' || rownum str from dual connect by rownum < 2
)

, indexed_strings as (
select str, row_number() over (order by 'x') rn, ',' separator from dummy_text
)

, hier (str, lvl) as (
select to_clob(i.str), rn from indexed_strings i where rn = (select max(rn) from indexed_strings)
union all
select concat(to_clob(concat(i.str, i.separator)), h.str), h.lvl - 1 from indexed_strings i join hier h on h.lvl - 1 = i.rn
)

select str from hier where lvl = 1