Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 处理递归(oracle)_Sql_Oracle_Oracle10g_Hierarchical Data_Recursive Query - Fatal编程技术网

Sql 处理递归(oracle)

Sql 处理递归(oracle),sql,oracle,oracle10g,hierarchical-data,recursive-query,Sql,Oracle,Oracle10g,Hierarchical Data,Recursive Query,我在尝试为客户网络交易做一些业务逻辑时遇到了一些问题: 我的客户有一个简化的表格,如下所示: || ID || OFFERED_PRODUCT_ID || DEMANDED_PRODUCT_ID || || 01 || 34 || 45 || || 01 || 34 || 16 || || 01 || 45 || 57

我在尝试为客户网络交易做一些业务逻辑时遇到了一些问题:

我的客户有一个简化的表格,如下所示:

|| ID ||  OFFERED_PRODUCT_ID  || DEMANDED_PRODUCT_ID ||
|| 01 ||  34                  || 45                  ||
|| 01 ||  34                  || 16                  ||
|| 01 ||  45                  || 57                  ||
|| 01 ||  47                  || 57                  ||
|| 01 ||  57                  || 63                  ||
|| 01 ||  16                  || 20                  ||
现在,应用程序必须显示最大的贸易链,贸易链定义为提供和需求产品之间的关系

这是贸易链:

<34,45,57,63>

我试图用C语言来解决这个问题,但由于数据量太大,这就变得不可能了。我的一位同事建议我使用递归。我试图理解他的意思,但我是一名客户端开发人员,对SQL不太了解

我做了这些:

  select  o.OFFERED_PRODUCT_ID, o.DEMANDED_PRODUCT_ID
  from TRADES o
  start with 
  o.DEMANDED_PRODUCT_ID = (SELECT MIN(o.DEMANDED_PRODUCT_ID) from TRADES)
  connect by NOCYCLE prior o.DEMANDED_PRODUCT_ID = o.OFFERED_PRODUCT_ID;
我试图用系统上最早的产品和最小标识符来启动递归。但它不起作用。它给了我所有的贸易链。我只需要最大的一个

下面是一个输出示例:

OFFERED_PRODUCT_ID      DEMANDED_PRODUCT_ID

9920896475501851        59587794888502550724
59587794888502550724    13197303523502765990
13197303523502765990    54010274740204405159
54010274740204405159    14505831337880766413
14505831337880766413    89607128670993987443
89607128670993987443    8802863939059413452
8802863939059413452  7779127922701247342
7779127922701247342  3810800421539873909
3810800421539873909  12423373218147473557

交易链的长度等于递归的深度。Oracle有一个psuedo变量LEVEL,您可以使用它。如果您接受原始查询并按级别排序,则最长链的末尾将位于第一位。然后我们需要消除查询的其余部分。 上面的命令将返回链中的最后一行。要在逗号分隔的列表中获取整个链,请执行以下操作: 您可能需要删除前导逗号。 如果您想要最长的链,一次一行: select c.OFFERED_PRODUCT_ID, c.DEMANDED_PRODUCT_ID from TRADES c start with (c.OFFERED_PRODUCT_ID, c.DEMANDED_PRODUCT_ID) in ( select o1, d1 from ( select level lvl, o.OFFERED_PRODUCT_ID, o.DEMANDED_PRODUCT_ID , CONNECT_BY_ROOT OFFERED_PRODUCT_ID o1 , CONNECT_BY_ROOT DEMANDED_PRODUCT_ID d1 from TRADES o start with o.OFFERED_PRODUCT_ID not in (select st.DEMANDED_PRODUCT_ID from trades st) connect by NOCYCLE prior o.DEMANDED_PRODUCT_ID = o.OFFERED_PRODUCT_ID order by level desc ) where rownum = 1 ) connect by NOCYCLE prior c.DEMANDED_PRODUCT_ID = c.OFFERED_PRODUCT_ID
CONNECT_BY_ROOT命令从递归的根(即链的第一行)获取数据。我正在运行10g Rel 2。我不确定它是否在旧版本上可用。

我相信你想要类似的东西

SQL> ed
Wrote file afiedt.buf

  1  with trades as (
  2    select 34 offered_product_id, 45 demanded_product_id from dual
  3    union all
  4    select 34, 16 from dual
  5    union all
  6    select 45, 57 from dual
  7    union all
  8    select 47, 57 from dual
  9    union all
 10    select 57, 63 from dual
 11    union all
 12    select 16, 20 from dual
 13  )
 14  select path
 15    from (
 16    select offered_product_id,
 17           demanded_product_id,
 18           level + 1,
 19           sys_connect_by_path( offered_product_id, '/' ) ||
 20              '/' || demanded_product_id path,
 21           dense_rank() over (order by level desc) rnk
 22      from trades
 23   connect by prior demanded_product_id = offered_product_id )
 24*  where rnk = 1
SQL> /

PATH
--------------------
/34/45/57/63
因为o。将其与主查询关联。这相当于以o开头。提供的产品ID不为空。我想你想要:
以上将给你所有的链条,但不会启动任何链条在中间。如果你只想要最长的链子,你显然不想从中间开始短的链条。 我想你可能需要换一下你的前任在哪里?如中所示:通过NOCYCLE o.REQUIRED_PRODUCT_ID=先前o.REQUIRED_PRODUCT_ID连接;没有。它与实际订单一起工作。只不过它不会返回最长的值。+1 select语句是一个很好的答案,并且提供的with子句可以方便地模拟真实的db数据。感谢您的回答。但我不能尝试。它说:ORA-01489:字符串连接的结果太长01489。00000-字符串连接结果太长*原因:字符串连接结果超过最大大小*措施:确保结果小于最大值。@Randolf-你的实际交易链有多长?从错误中听起来,SYS\u CONNECT\u BY\u PATH试图生成长度超过4000个字符的字符串。您可以取消该调用,在这种情况下,您将无法再获得路径,或者您可以找到其他方法来表示路径—可能有一个具有较短标识符的PRODUCT表,您可以加入?。不。没有一个:如果我删除SYS\u CONNECT\u BY\u路径,那么它开始执行,但从不停止。我添加了NOCYCLE子句,但即使这样它也没有停止:Define没有停止。我认为TRADES表可能相当大——查询可能需要一段时间才能运行。Hi。它开始执行,但没有任何响应。我正在本地局域网内尝试。只有20k个条目:S@RandolfR-F:检查您输入的对账单。当我将level添加到select列表中,并根据您在问题中给出的数据运行它时,它将返回一行3 57 63。这是最长链条的最后一行。但是你想要整个链条,对吗? select c.OFFERED_PRODUCT_ID, c.DEMANDED_PRODUCT_ID from TRADES c start with (c.OFFERED_PRODUCT_ID, c.DEMANDED_PRODUCT_ID) in ( select o1, d1 from ( select level lvl, o.OFFERED_PRODUCT_ID, o.DEMANDED_PRODUCT_ID , CONNECT_BY_ROOT OFFERED_PRODUCT_ID o1 , CONNECT_BY_ROOT DEMANDED_PRODUCT_ID d1 from TRADES o start with o.OFFERED_PRODUCT_ID not in (select st.DEMANDED_PRODUCT_ID from trades st) connect by NOCYCLE prior o.DEMANDED_PRODUCT_ID = o.OFFERED_PRODUCT_ID order by level desc ) where rownum = 1 ) connect by NOCYCLE prior c.DEMANDED_PRODUCT_ID = c.OFFERED_PRODUCT_ID
SQL> ed
Wrote file afiedt.buf

  1  with trades as (
  2    select 34 offered_product_id, 45 demanded_product_id from dual
  3    union all
  4    select 34, 16 from dual
  5    union all
  6    select 45, 57 from dual
  7    union all
  8    select 47, 57 from dual
  9    union all
 10    select 57, 63 from dual
 11    union all
 12    select 16, 20 from dual
 13  )
 14  select path
 15    from (
 16    select offered_product_id,
 17           demanded_product_id,
 18           level + 1,
 19           sys_connect_by_path( offered_product_id, '/' ) ||
 20              '/' || demanded_product_id path,
 21           dense_rank() over (order by level desc) rnk
 22      from trades
 23   connect by prior demanded_product_id = offered_product_id )
 24*  where rnk = 1
SQL> /

PATH
--------------------
/34/45/57/63
select level, o.OFFERED_PRODUCT_ID, o.DEMANDED_PRODUCT_ID, SYS_CONNECT_BY_PATH(o.OFFERED_PRODUCT_ID, ','), SYS_CONNECT_BY_PATH(o.DEMANDED_PRODUCT_ID, ',') , CONNECT_BY_ROOT OFFERED_PRODUCT_ID o1 , CONNECT_BY_ROOT DEMANDED_PRODUCT_ID d1 from TRADES o start with o.OFFERED_PRODUCT_ID not in (select st.DEMANDED_PRODUCT_ID from trades st) connect by NOCYCLE prior o.DEMANDED_PRODUCT_ID = o.OFFERED_PRODUCT_ID