如何避免递归的无限循环? (postgreSQL)

时间:2019-12-22 15:30:14

标签: sql postgresql

我必须提出另一个问题,这已经使我花费了几个小时,而我却无法解决它。我需要在PostgreSQL中编写一个递归查询(用于univercity)。我有一个称为“ basedOn”的关系,其中计算机基于其他(旧)版本,例如:

CREATE TABLE BasedON(
    fromID integer,
    fromSize numeric,
    toID integer,
    toSize numeric,
...
);

我需要知道使用递归查询查找基于其他版本的所有可传递版本(例如,如果A基于B,而B基于C,A基于C)。我现在的问题是,我还必须针对“基于B的B,基于C的B和基于A的C”的循环解决此问题,在该循环中我的查询会无限循环。那就是我的查询现在的样子:

WITH RECURSIVE tmp(fromID, fromSize, toID, toSize,c) AS (
                    SELECT fromID, fromSize, toID, toSize, 0 FROM BasedOn
                    WHERE toID= 0 AND toSize= 2.0 --start
                UNION 
                    SELECT b.fromID, b.fromSize,  t.toID,t.toSIze, c+1 AS steps
                    FROM BasedOn b JOIN tmp t ON
                                         t.fromID= b.toID AND t.fromSize= b.toSize
 )SELECT * FROM tmp;

“ c”仅用于“计算”递归步骤。它适用于非循环数据。但是,如果我在数据中插入一个循环,则会无限循环。有没有人给小费,如何避免这种情况? 提前致谢, 卢卡斯

SampleData:

INSERT INTO BasedOn VALUES 
                (7000, 1.28, 7003, 2.52),
                (7003, 2.52, 7006, 0.98), --cycle
                (7006, 0.98, 7009, 4.18),
                (7006, 0.98, 7003, 2.52), --cycle
                (7009, 4.18, 7015, 1.33),
                (7009, 4.18, 0, 2.00);

预期输出:

fromID, fromSize, toID, toSize,stepcount
7009    4.18    0   2.00    0
7006    0.98    0   2.00    1
7003    2.52    0   2.00    2
7000    1.28    0   2.00    3

2 个答案:

答案 0 :(得分:1)

去那里:


const App:React.FC<Props>=(props:Props)=> {
  const [data, setData] = React.useState<MyInterface[]>(props.values);

  const handleChange = (e: ChangeEvent<HTMLInputElement>,id:number) => {
    const amount = parseInt(e.target.value, 10);
    const temp:MyInterface[] = data.map(d => d.id === id? {...d,amount} : d)
    setData(temp);
  };

  const upload = ()=> { /* POST the state array to server */}

  return (
      <>
        {data.map(d=> (
         <div>
           <input value={d.amount} onChange={handleChange} />
           <button onClick={upload}/>
         </div>
        ))}  
      </>
 );
}

结果:


\i tmp.sql

CREATE TABLE based_on(
    from_id integer
    , from_size numeric
    , to_id integer
    , to_size numeric
);

INSERT INTO based_on VALUES
                (7000, 1.28, 7003, 2.52),
                (7003, 2.52, 7006, 0.98), --cycle
                (7006, 0.98, 7009, 4.18),
                (7006, 0.98, 7003, 2.52), --cycle
                (7009, 4.18, 7015, 1.33),
                (7009, 4.18, 0, 2.00);

-- I need know to find all transitive versions which base on others (like if A bases on B, and B on C, A bases on C) using a recursive Query. My Problem now is, that I have to solve this also for Cycles like "A bases on B, B on C, and C on A", where my query loops infinite. Thats what my query looks like now:

WITH RECURSIVE tmp(from_id, from_size, to_id, to_size,c,path) AS (
        SELECT from_id, from_size, to_id, to_size
                , 0
                , array[from_id] AS path
        FROM based_on
        WHERE to_id= 0 AND to_size= 2.0 --start
        UNION
        SELECT b.from_id, b.from_size
                ,  t.to_id,t.to_size
        , c+1 AS steps
        , t.path || b.from_id
        FROM based_on b
        JOIN tmp t ON t.from_id= b.to_id -- AND t.from_size= b.to_size
                AND NOT b.from_id = ANY(t.path)
        )
SELECT * FROM tmp;

答案 1 :(得分:1)

我只是为了好玩(?)而使用ARRAY做练习。

无论如何,这是查询:

with recursive
s as (
  select
    *, tosize as converted_size, 0 as step_count,
    array[-1]::int[] as walked, 1 as len from basedon 
  where toid = 0 and tosize = 2.0 -- starting node
  union all
  select b.*, s.converted_size, step_count + 1,
    walked || b.fromid, array_length(walked, 1) + 1
  from s
  join basedon b on b.toid = s.fromid and b.tosize = s.fromsize 
                and not (b.fromid = any(walked))
)
select * from s;

结果:

fromid  fromsize  toid  tosize  converted_size  step_count  walked        len
------  --------  ----  ------  --------------  ----------  ------------  ---
7009    4.18         0     2    2               0           <UnknownType  1  
7006    0.98      7009  4.18    2               1           <UnknownType  2  
7003    2.52      7006  0.98    2               2           <UnknownType  3  
7000    1.28      7003  2.52    2               3           <UnknownType  4  

这是我使用的数据脚本:

create table basedon (
  fromid integer,
  fromsize numeric,
  toid integer,
  tosize numeric
);

insert into basedon (fromid, fromsize, toid, tosize) values 
  (7000, 1.28, 7003, 2.52),
  (7003, 2.52, 7006, 0.98), --cycle
  (7006, 0.98, 7009, 4.18),
  (7006, 0.98, 7003, 2.52), --cycle
  (7009, 4.18, 7015, 1.33),
  (7009, 4.18, 0, 2.00);
相关问题