带JOIN元素的递归链?

时间:2014-02-18 14:06:10

标签: sql postgresql join recursive-cte

我最近在postgreSQL中要求recursive query。答案很合适,但只要我添加一个JOIN元素,它就会给我以下错误:

  

错误:缺少表“n”的FROM子句条目:WITH RECURSIVE链   AS(SELECT n.pordnr,pz.pordnrzu,n.abschl,n.stg,n.kzfa,n.pversion   FROM pord n LEFT JOIN pordnrzu pz ON pz.pordnr = n.pordnr WHERE   n.pordnr = 112 UNION ALL SELECT n.pordnr,pz2.pordnrzu,n.abschl,   n.stg,n.kzfa,n.pversion FROM chain c LEFT JOIN pordnrzu pz2 ON   pz2.pordnr = n.pordnr INNER JOIN pord n ON(c.pordnrzu = n.pordnr)   WHERE c.abschl IS NULL)SELECT * FROM chain c WHERE c.abschl IS NOT   NULL

我尝试了几次修改,但我无法让它工作。我想要的是,pordnrzu正在实施以寻找另一个pordnr

所以:pordnr - > pordnrzu - > pordnr

有什么我错过的吗?

这是样本表:

CREATE TABLE pord (
  pordnr integer primary key,
  abschl text,
  stg text,
  kzfa text,
  pversion text
);

INSERT INTO pord (pordnr, abschl, stg, kzfa, pversion)
VALUES
(112,     NULL, NULL, NULL, NULL),
(140,     NULL, NULL, NULL, NULL),
(200,     NULL, NULL, NULL, NULL),
(210,     'f2', '140', 'H', '2011'),
(220,     'f2222', '140000', 'HHH', '201111');

CREATE TABLE pordnrzu (
  pordnr integer primary key,
  pordnrzu integer
);

INSERT INTO pordnrzu (pordnr, pordnrzu)
VALUES
(112,     140),
(140,     210),
(200,     220),
(210,     220),
(220,     NULL);

现在我的查询:

WITH RECURSIVE chain AS
(
  SELECT n.pordnr, pz.pordnrzu, n.abschl, n.stg, n.kzfa, n.pversion
  FROM pord n
  LEFT JOIN pordnrzu pz
  ON pz.pordnr = n.pordnr
  WHERE n.pordnr = 112
  UNION ALL
  SELECT n.pordnr, pz2.pordnrzu, n.abschl, n.stg, n.kzfa, n.pversion
  FROM chain c
  LEFT JOIN pordnrzu pz2
  ON pz2.pordnr = n.pordnr
  INNER JOIN pord n ON (c.pordnrzu = n.pordnr)
  WHERE c.abschl IS NULL
)
SELECT *
FROM chain c
WHERE c.abschl IS NOT NULL;

我的目标是从pordnr=112开始,然后按pordnrzu引导到其他pordnr,直到找到第一个条目为abschl NOT NULL

在此示例中,解决方案将是此行:

pordnr   pordnrzu   abschl   stg   kzfa   pversion
200      210        f2       140   H      2011

SELECT version();
  

x86_64-unknown-linux-gnu上的PostgreSQL 9.2.6,由gcc编译(SUSE Linux)4.3.4 [gcc-4_3-branch revision 152973],64位

1 个答案:

答案 0 :(得分:1)

JOIN子句的评估为left-to-right。移动第二个联接以使其工作:

WITH RECURSIVE chain AS (
  SELECT n.pordnr, pz.pordnrzu, n.abschl, n.stg, n.kzfa, n.pversion
  FROM   pord n
  LEFT   JOIN pordnrzu pz ON pz.pordnr = n.pordnr
  WHERE  n.pordnr = 112

  UNION ALL
  SELECT n.pordnr, pz.pordnrzu, n.abschl, n.stg, n.kzfa, n.pversion
  FROM   chain c
  JOIN   pord  n ON n.pordnr = c.pordnrzu
  LEFT   JOIN pordnrzu pz ON pz.pordnr = n.pordnr
  WHERE  c.abschl IS NULL
)
SELECT *
FROM   chain c
WHERE  c.abschl IS NOT NULL;

或者,您可以在第二个SELECT中重写第一个JOIN:

LEFT   JOIN pordnrzu pz ON pz.pordnr = c.pordnrzu