Sybase IQ SQL递归循环构建树

时间:2017-01-10 14:41:38

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

我需要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');

预期输出

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

1 个答案:

答案 0 :(得分:0)

这是我迄今为止所做的以及它在自我加入方面的作用。 我唯一担心的是自我加入是缓慢或相当混乱。

我也尝试用锚点(但在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;

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

有什么建议吗?