簡體   English   中英

LISTAGG oracle function 結果不正確

[英]LISTAGG oracle function incorrect results

我想咨詢聚合 function LISTAGG 的這個問題:

select 
r.id, 
(
select
    LISTAGG(
        r.id || '##' || cco.id  
            , 
        ' '
    )
    from 
    (
        SELECT
            co.id
       FROM conditions co
       START WITH ID = (select cons.id from conditions cons where cons.role_id = r.id)
       CONNECT BY PRIOR co.id = co.parent_condition_id
    ) cco
) conditions_export

from roles r
where r.id in (570, 571, 569)
--r.id between 569 and 571



-- table roles has 2 fields: id (number), name (varchar2)
-- table conditions has 4 fields: id, parent_condition_id, role_id (number), rule (varchar2)

當我在條件r.id in (570, 571, 569)中使用單個 id(或顯式 ID 列表)時,結果符合預期。

當我不使用 where 子句或使用一些動態范圍時( r.id between 569 and 571 , r.id > 500 , r.id in (select rr.id from roles rr) ),結果包含相同的聚合值對於每一行 - 結果是錯誤的(不符合預期)。

我的數據庫中的示例:

表角色中的值:

id   name
---  -----
569  ROLE1
570  ROLE2
571  ROLE3

表條件中的值:

id    parent_condition_id   role_id  rule
------------------------------------------
1657  NULL                  569      deny
1659  NULL                  570      allow
1667  NULL                  571      and
1674  1668                  NULL     match
1673  1670                  NULL     allow
1672  1671                  NULL     allow
1671  1670                  NULL     and
1670  1669                  NULL     and
1669  1668                  NULL     and
1668  1667                  NULL     and

查詢: ... r.id in (570, 571, 569)結果:

569 569##1657
570 570##1659
571 571##1667 571##1668 571##1669 571##1670 571##1671 571##1672 571##1673 571##1674

查詢: ... r.id between 569 and 571結果:

569 569##1657
570 570##1657
571 571##1657

使用此聚合的原因是將當前配置從數據庫導出到文本文件。

問題:你有什么想法,如何解決這個問題?

數據庫版本為 Oracle 19c

您可以使用遞歸子查詢分解而不是分層查詢:

with rcte (role_id, condition_id) as (
  select r.id, c.id
  from roles r
  left join conditions c on c.role_id = r.id
  where r.id in (570, 571, 569)
  union all
  select rcte.role_id, c.id
  from rcte
  join conditions c on c.parent_condition_id = rcte.condition_id
)
select rcte.role_id,
  listagg(rcte.role_id || '##' || rcte.condition_id, ' ')
from rcte
group by rcte.role_id
order by rcte.role_id;
角色編號 LISTAGG(RCTE.ROLE_ID||'##'||RCTE.CONDITION_ID,'')
569 569##1657
570 570##1659
571 571##1667 571##1668 571##1674 571##1669 571##1670 571##1673 571##1671 571##1672

fiddle包括您的各種初始查詢及其結果。

錨點成員獲取角色和初始條件; 然后遞歸成員查找任何子條件。


第一個問題是結果條件的順序不同

您的原始代碼沒有任何條件排序,因此結果是不確定的。

在您的示例 output 中,它們似乎按條件 ID 排序,因此您可以明確地執行此操作:

select rcte.role_id,
  listagg(rcte.role_id || '##' || rcte.condition_id, ' ')
    within group (order by rcte.condition_id) as conditions
from rcte
角色編號 狀況
569 569##1657
570 570##1659
571 571##1667 571##1668 571##1669 571##1670 571##1671 571##1672 571##1673 571##1674

正如您提到的級別,您可能希望按該級別排序,盡管它為您的示例提供了不同的結果。 您可以通過跟蹤 CTE 中的虛擬列來獲取級別(我將其稱為lvl ,因為level是為分層語法保留的):

with rcte (role_id, lvl, condition_id) as (
  select r.id, 1, c.id
  from roles r
  left join conditions c on c.role_id = r.id
  where r.id in (570, 571, 569)
  union all
  select rcte.role_id, rcte.lvl + 1, c.id
  from rcte
  join conditions c on c.parent_condition_id = rcte.condition_id
)
select rcte.role_id,
  listagg(rcte.role_id || '##' || rcte.condition_id, ' ')
    within group (order by rcte.lvl) as conditions
from rcte
group by rcte.role_id
order by rcte.role_id;
角色編號 狀況
569 569##1657
570 570##1659
571 571##1667 571##1668 571##1669 571##1674 571##1670 571##1671 571##1673 571##1672

或者您可以按級別排序,然后按條件排序,其中同一級別有多個條件(即多個條件具有相同的父項); 有了這些數據,它沒有什么區別,但如果有多個數據,它會保持確定性:

select rcte.role_id,
  listagg(rcte.role_id || '##' || rcte.condition_id, ' ')
    within group (order by rcte.lvl, rcte.condition_id) as conditions
from rcte
角色編號 狀況
569 569##1657
570 570##1659
571 571##1667 571##1668 571##1669 571##1674 571##1670 571##1671 571##1673 571##1672

小提琴

第二個問題是我無法訪問“LEVEL”變量

您問題中的代碼沒有引用它,但如上所示,您可以將其生成為lvl虛擬列。 目前尚不清楚您將如何使用它 - 如果您希望它出現在 select 列表中,那么您將不得不按它進行分組,這會得到非常不同的結果。 您可以改為包含max(lvl) 或者將lvl連接到條件中(例如571#1#1667 )。 目前還不清楚你想用它做什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM