从递归查询中删除行
Remove rows from recursive query
当我在我的数据库中 运行 这个查询时,我得到以下信息:
WITH RECURSIVE series AS (
SELECT CONCAT( a.title) as str, a.prequelID
FROM ( Prequels NATURAL JOIN Books) AS a
UNION
SELECT CONCAT(t.title, ' -> ', str) as str, t.prequelID
FROM (Books NATURAL JOIN Prequels) as t
INNER JOIN series AS s ON s.prequelID = t.bookID
)
SELECT str as series FROM series
ORDER BY series;
这是结果:
我不想要任何重复,只想要显示整个系列的完整字符串。
我该怎么做?
更新:
我更新了查询,因为我意识到我错过了该系列的第一本书。
WITH RECURSIVE series AS (
SELECT CONCAT( a.title) as str, a.prequelID
FROM ( Prequels NATURAL JOIN Books) AS a
UNION
SELECT CONCAT(t.title, ' -> ', str) as str, t.prequelID
FROM (Books NATURAL JOIN Prequels) as t
INNER JOIN series AS s ON s.prequelID = t.bookID
)
SELECT CONCAT(a.title, ' -> ',a.str) as series
FROM (
SELECT Books.title, series.str
FROM series JOIN Books ON series.prequelID = Books.bookID
WHERE NOT EXISTS(
SELECT prequelID
FROM Prequels
WHERE series.prequelID = Prequels.bookID
)
) a
ORDER BY series;
结果还是有点偏差,因为我只想要系列的完整字符串:
我该如何解决这个问题?
表格:
CREATE TABLE Books
(bookID integer PRIMARY KEY,
title varchar(100),
pages integer);
CREATE TABLE Prequels
(bookID INTEGER REFERENCES Books(bookID),
prequelID INTEGER REFERENCES Books(bookID),
PRIMARY KEY (bookID,prequelID));
《权力的游戏》系列示例数据:
INSERT INTO BOOKS (bookID,title,pages) VALUES (80429,'A Game of Thrones',292);
INSERT INTO BOOKS (bookID,title,pages) VALUES (41121,'A Clash of Kings',160);
INSERT INTO BOOKS (bookID,title,pages) VALUES (29287,'A Storm of Swords',160);
INSERT INTO BOOKS (bookID,title,pages) VALUES (17696,'A Feast for Crows',292);
INSERT INTO BOOKS (bookID,title,pages) VALUES (3947,'A Dance with Dragons',101);
INSERT INTO Prequels (bookID,prequelID) VALUES (41121,80429);
INSERT INTO Prequels (bookID,prequelID) VALUES (29287,41121);
INSERT INTO Prequels (bookID,prequelID) VALUES (17696,29287);
INSERT INTO Prequels (bookID,prequelID) VALUES (3947,17696);
递归查询后,可以将所有str与自连接进行比较,保留不属于任何[=12的子串的s1.str
=] 感谢 WHERE s2.str IS NULL
子句。
WITH RECURSIVE series AS (
SELECT CONCAT( a.title) as str, a.prequelID
FROM ( Prequels NATURAL JOIN Books) AS a
UNION
SELECT CONCAT(t.title, ' -> ', str) as str, t.prequelID
FROM (Books NATURAL JOIN Prequels) as t
INNER JOIN series AS s ON s.prequelID = t.bookID
)
SELECT s1.str as series
FROM series AS s1
LEFT JOIN series AS s2
ON s2.str ~ s1.str
AND s2.str <> s1.str
WHERE s2.str IS NULL
ORDER BY series;
测试结果在dbfiddle
你想从树根开始。
prequelId 中没有根。
WITH RECURSIVE series AS (
SELECT
b.bookId
, 1 as lvl
, p.prequelID
, CONCAT(b.title) as series
FROM Books AS b
LEFT JOIN Prequels AS p
ON p.bookId = b.bookId
WHERE NOT EXISTS (
SELECT 1
FROM Prequels p2
WHERE p2.prequelID = b.bookId
)
UNION ALL
SELECT
s.bookId
, s.lvl+1
, p.prequelID
, CONCAT(b.title, ' -> ', s.series)
FROM series AS s
JOIN Books AS b
ON b.bookId = s.prequelID
LEFT JOIN Prequels AS p
ON p.bookId = s.prequelID
)
SELECT series
FROM series
WHERE prequelId is null
AND lvl > 1
ORDER BY series;
series
A Game of Thrones -> A Clash of Kings -> A Storm of Swords -> A Feast for Crows -> A Dance with Dragons
演示 db<>fiddle here
LukStorms 修改版现已删除答案...
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=4e26beed430aefb60f1dc91766db13d3
WITH RECURSIVE series AS (
SELECT
b.bookId,
1 as lvl,
p.prequelID,
CONCAT(b.title) AS series
FROM
books b
LEFT JOIN
prequels p
ON p.bookid = b.bookid
WHERE NOT EXISTS (
SELECT 1
FROM Prequels p
WHERE p.prequelID = b.bookId
)
UNION ALL
SELECT
b.bookid,
lvl+1,
p.prequelID,
CONCAT(b.title, ' -> ', s.series)
FROM
series s
INNER JOIN
books b
ON b.bookid = s.prequelid
LEFT JOIN
prequels p
ON p.bookid = b.bookid
)
SELECT
s.series
FROM
series s
WHERE
s.prequelid IS NULL
ORDER BY
s.series;
CTE 的非递归部分有一个 LEFT JOIN,以便包括不属于系列的书籍,只是一本独立的书籍。如果您不想要,请将其恢复为 NATURAL 或 INNER JOIN。
CTE 的非递归部分有一个 WHERE 子句,以确保它只从系列的最后一本书开始。
CTE 的递归部分在前传中有一个 LEFT JOIN table,因此系列中的第一本书不会丢失(由于没有前传行),因此记录本书的前传为 NULL。
外部查询然后查找该 NULL,因此只输出已完成系列的行。
当我在我的数据库中 运行 这个查询时,我得到以下信息:
WITH RECURSIVE series AS (
SELECT CONCAT( a.title) as str, a.prequelID
FROM ( Prequels NATURAL JOIN Books) AS a
UNION
SELECT CONCAT(t.title, ' -> ', str) as str, t.prequelID
FROM (Books NATURAL JOIN Prequels) as t
INNER JOIN series AS s ON s.prequelID = t.bookID
)
SELECT str as series FROM series
ORDER BY series;
这是结果:
我不想要任何重复,只想要显示整个系列的完整字符串。 我该怎么做?
更新:
我更新了查询,因为我意识到我错过了该系列的第一本书。
WITH RECURSIVE series AS (
SELECT CONCAT( a.title) as str, a.prequelID
FROM ( Prequels NATURAL JOIN Books) AS a
UNION
SELECT CONCAT(t.title, ' -> ', str) as str, t.prequelID
FROM (Books NATURAL JOIN Prequels) as t
INNER JOIN series AS s ON s.prequelID = t.bookID
)
SELECT CONCAT(a.title, ' -> ',a.str) as series
FROM (
SELECT Books.title, series.str
FROM series JOIN Books ON series.prequelID = Books.bookID
WHERE NOT EXISTS(
SELECT prequelID
FROM Prequels
WHERE series.prequelID = Prequels.bookID
)
) a
ORDER BY series;
结果还是有点偏差,因为我只想要系列的完整字符串:
我该如何解决这个问题?
表格:
CREATE TABLE Books
(bookID integer PRIMARY KEY,
title varchar(100),
pages integer);
CREATE TABLE Prequels
(bookID INTEGER REFERENCES Books(bookID),
prequelID INTEGER REFERENCES Books(bookID),
PRIMARY KEY (bookID,prequelID));
《权力的游戏》系列示例数据:
INSERT INTO BOOKS (bookID,title,pages) VALUES (80429,'A Game of Thrones',292);
INSERT INTO BOOKS (bookID,title,pages) VALUES (41121,'A Clash of Kings',160);
INSERT INTO BOOKS (bookID,title,pages) VALUES (29287,'A Storm of Swords',160);
INSERT INTO BOOKS (bookID,title,pages) VALUES (17696,'A Feast for Crows',292);
INSERT INTO BOOKS (bookID,title,pages) VALUES (3947,'A Dance with Dragons',101);
INSERT INTO Prequels (bookID,prequelID) VALUES (41121,80429);
INSERT INTO Prequels (bookID,prequelID) VALUES (29287,41121);
INSERT INTO Prequels (bookID,prequelID) VALUES (17696,29287);
INSERT INTO Prequels (bookID,prequelID) VALUES (3947,17696);
递归查询后,可以将所有str与自连接进行比较,保留不属于任何[=12的子串的s1.str
=] 感谢 WHERE s2.str IS NULL
子句。
WITH RECURSIVE series AS (
SELECT CONCAT( a.title) as str, a.prequelID
FROM ( Prequels NATURAL JOIN Books) AS a
UNION
SELECT CONCAT(t.title, ' -> ', str) as str, t.prequelID
FROM (Books NATURAL JOIN Prequels) as t
INNER JOIN series AS s ON s.prequelID = t.bookID
)
SELECT s1.str as series
FROM series AS s1
LEFT JOIN series AS s2
ON s2.str ~ s1.str
AND s2.str <> s1.str
WHERE s2.str IS NULL
ORDER BY series;
测试结果在dbfiddle
你想从树根开始。
prequelId 中没有根。
WITH RECURSIVE series AS (
SELECT
b.bookId
, 1 as lvl
, p.prequelID
, CONCAT(b.title) as series
FROM Books AS b
LEFT JOIN Prequels AS p
ON p.bookId = b.bookId
WHERE NOT EXISTS (
SELECT 1
FROM Prequels p2
WHERE p2.prequelID = b.bookId
)
UNION ALL
SELECT
s.bookId
, s.lvl+1
, p.prequelID
, CONCAT(b.title, ' -> ', s.series)
FROM series AS s
JOIN Books AS b
ON b.bookId = s.prequelID
LEFT JOIN Prequels AS p
ON p.bookId = s.prequelID
)
SELECT series
FROM series
WHERE prequelId is null
AND lvl > 1
ORDER BY series;
series |
---|
A Game of Thrones -> A Clash of Kings -> A Storm of Swords -> A Feast for Crows -> A Dance with Dragons |
演示 db<>fiddle here
LukStorms 修改版现已删除答案...
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=4e26beed430aefb60f1dc91766db13d3
WITH RECURSIVE series AS (
SELECT
b.bookId,
1 as lvl,
p.prequelID,
CONCAT(b.title) AS series
FROM
books b
LEFT JOIN
prequels p
ON p.bookid = b.bookid
WHERE NOT EXISTS (
SELECT 1
FROM Prequels p
WHERE p.prequelID = b.bookId
)
UNION ALL
SELECT
b.bookid,
lvl+1,
p.prequelID,
CONCAT(b.title, ' -> ', s.series)
FROM
series s
INNER JOIN
books b
ON b.bookid = s.prequelid
LEFT JOIN
prequels p
ON p.bookid = b.bookid
)
SELECT
s.series
FROM
series s
WHERE
s.prequelid IS NULL
ORDER BY
s.series;
CTE 的非递归部分有一个 LEFT JOIN,以便包括不属于系列的书籍,只是一本独立的书籍。如果您不想要,请将其恢复为 NATURAL 或 INNER JOIN。
CTE 的非递归部分有一个 WHERE 子句,以确保它只从系列的最后一本书开始。
CTE 的递归部分在前传中有一个 LEFT JOIN table,因此系列中的第一本书不会丢失(由于没有前传行),因此记录本书的前传为 NULL。
外部查询然后查找该 NULL,因此只输出已完成系列的行。