【问题标题】:Sybase IQ SQL Recursive Loop To Build TreeSybase IQ SQL 递归循环构建树
【发布时间】:2017-05-25 02:21:14
【问题描述】:

我需要 Sybase IQ 并且需要在一个表上构建一个树,该表包含超过一百万条记录,它链接每个 order_id。我需要找到它被现有order_id 替换的内容,直到最后。最终,我还需要找到每个 order_id 的各种数量并从中获得最大收益。

版本信息:

select @@version
SAP IQ/16.0.110.2014/10214/P/sp11/Enterprise Linux64 - x86_64 - 2.6.18-194.el5/64bit/2015-11-21 01:29:07

表 DDL

create table #tmporder 
(
account_key varchar(50) not null,
order_id varchar(50) not null,
msg_type  varchar(5) not null,
repl_by_order varchar(50) not null,
replaces_order varchar(50) not null,
quantity numeric(12) not null,
order_datetime datetime not null,
order_status varchar(1) not null
);

样本数据:

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6473','PL','0','0',1000,{ts '2016-10-07 07:59:10'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6473','MO','6480','0',1000,{ts '2016-10-07 07:59:10'},'5');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6474','PL','0','0',1000,{ts '2016-10-07 08:16:05'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6474','MO','6477','0',1000,{ts '2016-10-07 08:16:05'},'5');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6475','PL','0','0',1000,{ts '2016-10-07 08:16:18'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6475','MO','6476','0',1000,{ts '2016-10-07 08:16:18'},'5');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6476','MO','0','6475',1000,{ts '2016-10-07 08:18:59'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6477','MO','0','6474',1000,{ts '2016-10-07 08:19:39'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6477','MO','6478','6474',1000,{ts '2016-10-07 08:19:39'},'5');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6478','MO','6479','6477',1000,{ts '2016-10-07 08:25:42'},'5');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6478','MO','0','6477',1000,{ts '2016-10-07 08:25:42'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6479','MO','0','6478',1000,{ts '2016-10-07 08:29:00'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6480','MO','6481','6473',2000,{ts '2016-10-07 08:33:57'},'5');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6480','MO','0','6473',2000,{ts '2016-10-07 08:33:57'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6481','MO','0','6480',2000,{ts '2016-10-07 08:35:40'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6481','MO','6482','6480',2000,{ts '2016-10-07 08:35:40'},'5');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6482','MO','0','6481',2000,{ts '2016-10-07 08:36:40'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6484','PL','0','0',4000,{ts '2016-10-07 08:45:42'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6485','PL','0','0',1000,{ts '2016-10-07 08:46:30'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6486','PL','0','0',1000,{ts '2016-10-07 09:10:19'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6495','PL','0','0',1000,{ts '2016-10-07 17:54:10'},'1');

INSERT INTO #tmporder (account_key,order_id,msg_type,repl_by_order,replaces_order,quantity,order_datetime,order_status) 
VALUES ('123456','6496','PL','0','0','500',{ts '2016-10-07 18:05:24.0'},'1');

预期输出:

  • 订单编号:6473,相关订单编号:6473/6480/6481/6482,最大(数量):2000
  • 订单编号:6474,相关订单编号:6474/6477/6478/6479,最大(数量):1000
  • 订单编号:6475,相关订单编号:6475/6476,最大(数量):1000
  • 订单 ID:6484,相关订单 ID:,最大(数量):4000
  • 订单 ID:6485,相关订单 ID:,最大(数量):1000

【问题讨论】:

    标签: sql recursion tree parent-child sap-iq


    【解决方案1】:

    这是我到目前为止所做的,它的自我加入。 我对 self join 的唯一担心是速度慢或相当混乱。

    我还尝试使用锚点(但在 Oracle 中)进行 CTE,以满足相同的要求。不幸的是,Sybase IQ 不支持 RECURSIVE。(它给了我各种错误,例如;不允许使用 RECURSIVE,“远程服务器没有能力支持此语句”

    所以现在我已经实现了一个粗略的方式(为了理解,我分为多个步骤)。

    最初用根元素填充,通过创建临时层次结构表:

    create table #tmporder_hier 
    (
    account_key varchar(50) not null,
    order_id varchar(50) not null,
    replaces_order varchar(50) not null,
    quantity numeric(12) not null,
    root     varchar(20)     not null,
    path     varchar(600)    not null,
    depth    int             not null,
    multiple_qty     varchar(600)    not null,
    max_quantity numeric(12) null
    );
    
    insert into #tmporder_hier (account_key,order_id,replaces_order,quantity,root,path,depth,multiple_qty,max_quantity)
    select e.account_key,e.order_id,e.replaces_order,e.quantity, 
            e.order_id as root,
            '/' + e.order_id as path,
            1 as depth,
            '/' + convert(varchar(20),e.quantity) as multiple_qty,
            null as max_quantity
    from 
    #tmporder e
    where e.repl_by_order = '0' AND e.replaces_order = '0';
    

    然后我应用一个循环来找出每个父项的子条目并填充 PATH。

    DECLARE @i int
    DECLARE @rowcount int
    set @i=1;
    while @i <= 15
    BEGIN
           insert into #tmporder_hier(account_key,order_id,replaces_order,quantity,root,path,depth,multiple_qty,max_quantity)
           with tmpcte as
           ( select * from #tmporder_hier)
            SELECT distinct e.account_key,e.order_id,e.replaces_order,e.quantity
            ,e.replaces_order as root,
            t.path + '/' + e.order_id as path,
             @i + 1 as depth,
             t.multiple_qty + '/' + convert(varchar(20),e.quantity) as multiple_qty,null as max_quantity
             FROM #tmporder e , tmpcte t
             WHERE exists (
                                SELECT 1
                                   FROM #tmporder_hier h1
                                   where e.replaces_order = h1.order_id
                                    and e.account_key = h1.account_key
                                  )
            and e.replaces_order = t.order_id
            and not exists (select 1 from tmpcte t1 where e.order_id = t1.order_id and e.account_key = t1.account_key)
            set @rowcount = @@ROWCOUNT
            if (@rowcount = 0)
             break
            set @i = @i + 1
    END
    

    然后作为第三步,我用正确的条目更新 ROOT。

    update #tmporder_hier
    set root = case when charindex('/',right(path,char_length(path)-1))-1 = -1 
                then substring(path,2,char_length(path)-1) 
            else
                substring(path,2,charindex('/',right(path,char_length(path)-1))-1) 
            end,
        path = case when depth = 1 
                then '''' + substring(path,2,char_length(path)-1) + ''''
            else 
                ''''+str_replace(substring(path,2,char_length(path)-1),'/',''',''') + ''''
            end;
    

    最后一步,为了有一个干净的表集,我从 #tmporder_hier 中删除了不必要的记录:

    select *,max(depth) over (partition by account_key,root) as max_depth into #tmporder_hier_new
                                    from #tmporder_hier;
    
    
    delete from #tmporder_hier_new
    where 0 = case when depth = max_depth then 1 else 0 end;
    

    我正在寻找更好的解决方案。

    有什么建议吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-22
      • 2013-10-24
      • 2015-03-18
      相关资源
      最近更新 更多