3

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

我的客户有一张像这样的表(简化):

|| 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> <34、16、20> <45、57、63> <47、57、63> <57、63> <16、20>

我尝试使用 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
4

3 回答 3

4

我相信你想要类似的东西

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
于 2011-02-16T22:12:11.383 回答
3

交易链的长度等于递归的深度。Oracle 有一个可以使用的伪变量 LEVEL。如果您采用原始查询并按 LEVEL 排序,则最长链的末尾将是第一个。然后我们需要消除查询的其余部分。

选择 *
  从
  (选择o.OFFERED_PRODUCT_ID,o.DEMANDED_PRODUCT_ID
      从贸易 o
      从 o.DEMANDED_PRODUCT_ID = 开始
                (从 TRADES 中选择 MIN(o.DEMANDED_PRODUCT_ID))
      o.DEMANDED_PRODUCT_ID = o.OFFERED_PRODUCT_ID 之前通过 NOCYCLE 连接
      按层顺序排列
   )
  其中rownum = 1;

The above will return the last row in the chain. To get the entire chain in a comma seperated list:

select lvl,   opath ||','|| DEMANDED_PRODUCT_ID chain
from (
select level lvl,  o.OFFERED_PRODUCT_ID, o.DEMANDED_PRODUCT_ID, SYS_CONNECT_BY_PATH(o.OFFERED_PRODUCT_ID, ',') opath
  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
  order by level desc
)
where rownum = 1

您可能想要删除前导逗号。

如果你想要最长的链,一次一行:

选择 c.OFFERED_PRODUCT_ID、c.DEMANDED_PRODUCT_ID
  从贸易 c
  以 (c.OFFERED_PRODUCT_ID, c.DEMANDED_PRODUCT_ID) 开头
            (
             选择 o1, d1
              从 (
                       选择等级 lvl, o.OFFERED_PRODUCT_ID, o.DEMANDED_PRODUCT_ID
                          , CONNECT_BY_ROOT OFFERED_PRODUCT_ID o1
                          , CONNECT_BY_ROOT DEMANDED_PRODUCT_ID d1
                         从贸易 o
                         从不包含 o.OFFERED_PRODUCT_ID 开始(从交易 st 中选择 st.DEMANDED_PRODUCT_ID)
                         o.DEMANDED_PRODUCT_ID = o.OFFERED_PRODUCT_ID 之前通过 NOCYCLE 连接
                        按层顺序排列
                    )
                  其中rownum = 1
            )
   通过 NOCYCLE 之前的连接 c.DEMANDED_PRODUCT_ID = c.OFFERED_PRODUCT_ID

CONNECT_BY_ROOT命令从递归的根,即链的第一行获取数据。我在 10g Rel 2 上运行。我不确定它是否适用于旧版本。

于 2011-02-16T22:05:49.207 回答
0

您拥有的start with子句几乎没有任何作用,因为“o”。将其与主查询相关联。它相当于start with o.OFFERED_PRODUCT_ID is not null。我想你想要:

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

以上将为您提供所有链,但不会在“中间”启动任何链。如果您只想要最长的链条,您显然不想要从“中间”开始的较短链条。

于 2011-02-17T16:49:04.293 回答