我的数据库中有以下表格:
create table (
name varchar(25),
value int,
predecessor varchar(25)
);
包含样本数据:
name | value | predecessor
---------------+-------+---------------
buyingredients | 10 | null
eat | 3 | cook
cook | 12 | mixingredients
mixingredients | 5 | buyingredients
我想要一个选择name
和value
的SQL查询,这个查询是有序的,因此具有前驱null
的项是第一个,然后是谁的前任的行等于该行的名字是下一个等等(即购买者,搅拌者,做饭,吃饭)。
排序是严格线性的 - 如果两行具有相同的前导值,则行为是未定义的。
我正在努力寻找能够产生我想要的排序的SQL查询。我真的不知道从哪里开始。
我正在使用Informix数据库,但SQL的任何变体都是一个有用的起点。
已更新,以反映排序不按字母顺序
的事实答案 0 :(得分:2)
在具有公用表表达式的Transact-SQL中:
WITH LinkedList (name, value, predecessor, ordering)
AS
(
SELECT a.name, a.value, a.predecessor, 0
FROM YourTable a
WHERE a.predecessor IS NULL
UNION ALL
SELECT b.name, b.value, b.predecessor, c.ordering + 1
FROM YourTable b
INNER JOIN LinkedList c
ON b.predecessor = c.name
)
SELECT d.name, d.value
FROM LinkedList d
ORDER BY d.ordering, d.name
我不知道Informix是否有这个构造,但你所要求的本质上是一个递归查询,常见的表表达式在Transact-SQL中为你提供。
答案 1 :(得分:2)
Informix不支持WITH子句,更不用说WITH RECURSIVE了。这使得这些方法无法运作。没有特别干净的方法。如果您有两个或三个列表,还不完全清楚您是处理简单列表(示例是列表)还是更一般的树结构,这一点并不完全清楚。
但是,您可以创建一个临时表,并使用存储过程中的循环填充该表,然后以适当的顺序从临时表中进行选择。这很繁琐而不是非常困难。您先对表格进行广度搜索。我注意到你没有给你的桌子命名 - 所以它在下文中被称为'匿名'。
CREATE TEMP TABLE Flattened
(
Hierarchy SERIAL,
Level INTEGER,
Name VARCHAR(25),
Value INTEGER,
Predecessor VARCHAR(25)
);
CREATE TEMP TABLE Intermediate
(
Hierarchy SERIAL,
Level INTEGER,
Name VARCHAR(25),
Value INTEGER,
Predecessor VARCHAR(25)
);
INSERT INTO Flattened(Hierarchy, Level, Name, Value, Predecessor)
SELECT 0, 0, name, value, predecessor
FROM Anonymous
WHERE Predecessor IS NULL;
WHILE ...any rows were inserted into table...
INSERT INTO Intermediate(Hierarchy, Level, Name, Value, Predecessor)
SELECT F.Hierarchy, F.Level + 1, A.Name, A.Value, A.Predecessor
FROM Flattened AS F, Anonymous AS A
WHERE F.Name = A.Predecessor
AND F.Level = (SELECT MAX(Level) FROM Flattened);
INSERT INTO Flattened SELECT * FROM Intermediate;
DELETE FROM Intermediate;
END WHILE
DROP TABLE Intermediate;
现在你可以使用:
SELECT Name, Value, Predecessor
FROM Flattened
ORDER BY Hierarchy, Level, Name;
唯一剩下的棘手的一点是计算插入了多少行。在存储过程中,最简单的方法是:
SELECT COUNT(*) INTO n_count FROM Flattened;
和
LET o_count = n_count - 1;
WHILE o_count != n_count
...as above - two INSERT operations and a DELETE operation
LET o_count = n_count;
SELECT COUNT(*) INTO n_count FROM Flattened;
END WHILE;
总而言之,这对我有用(在已记录的数据库中)。
BEGIN;
CREATE TABLE Anonymous
(
Name VARCHAR(25),
Value INTEGER,
Predecessor VARCHAR(25)
);
INSERT INTO Anonymous VALUES("buyingredients", 10, NULL);
INSERT INTO Anonymous VALUES("eat", 3, "cook");
INSERT INTO Anonymous VALUES("cook", 12, "mixingredients");
INSERT INTO Anonymous VALUES("mixingredients", 5, "buyingredients");
CREATE PROCEDURE Flatten_Anonymous()
DEFINE old_count INTEGER;
DEFINE new_count INTEGER;
CREATE TEMP TABLE Flattened
(
Hierarchy SERIAL,
Level INTEGER,
Name VARCHAR(25),
Value INTEGER,
Predecessor VARCHAR(25)
);
CREATE TEMP TABLE Intermediate
(
Hierarchy SERIAL,
Level INTEGER,
Name VARCHAR(25),
Value INTEGER,
Predecessor VARCHAR(25)
);
INSERT INTO Flattened(Hierarchy, Level, Name, Value, Predecessor)
SELECT 0, 0, name, value, predecessor
FROM Anonymous
WHERE Predecessor IS NULL;
SELECT COUNT(*) INTO new_count FROM Flattened;
LET old_count = new_count - 1;
WHILE old_count != new_count
INSERT INTO Intermediate(Hierarchy, Level, Name, Value, Predecessor)
SELECT F.Hierarchy, F.Level + 1, A.Name, A.Value, A.Predecessor
FROM Flattened AS F, Anonymous AS A
WHERE F.Name = A.Predecessor
AND F.Level = (SELECT MAX(Level) FROM Flattened);
INSERT INTO Flattened SELECT * FROM Intermediate;
DELETE FROM Intermediate;
LET old_count = new_count;
SELECT COUNT(*) INTO new_count FROM Flattened;
END WHILE
DROP TABLE Intermediate;
END PROCEDURE;
EXECUTE PROCEDURE Flatten_Anonymous();
SELECT Name, Value, Predecessor
FROM Flattened
ORDER BY Hierarchy, Level, Name;
DROP TABLE Flattened;
ROLLBACK;
输出结果为:
buyingredients 10
mixingredients 5 buyingredients
cook 12 mixingredients
eat 3 cook
测试平台:在MacOS X 10.6.7上运行的Informix 11.70.FC2。
未使用多个独立层次结构或使用树状结构层次结构而非简单列表进行正式测试。
答案 2 :(得分:1)
我正在使用Informix数据库 SQL的任何变体都是有用的 起点。
我对Informix一无所知,所以这里是SQL Server的一个版本。
@T
是表变量,我用作测试表。要链接行,我使用递归CTE。
declare @T table
(
name varchar(25),
value int,
predecessor varchar(25)
)
insert into @T
select 'buyingredients', 10, null union all
select 'cook', 12, 'mixingredients' union all
select 'mixingredients', 5, 'buyingredients' union all
select 'eat', 3, 'cook'
;with cte as
(
select T.name,
T.value,
T.predecessor,
1 as sortorder
from @T as T
where T.predecessor is null
union all
select T.name,
T.value,
T.predecessor,
C.sortorder+1 as sortorder
from @T as T
inner join cte as C
on T.predecessor = C.name
)
select C.name,
C.value,
C.predecessor
from cte as C
order by C.sortorder
您可以在此处试用:http://data.stackexchange.com/stackoverflow/q/102534/recursive-cte-to-build-a-chain
修改强>
我仍然对Informix一无所知,但也许您可以使用Node DataBlade Module
执行某些操作答案 3 :(得分:0)
我认为做你想做的事情的方法是为每个项目构建一个带有“深度”字段的临时表,然后使用该深度字段来排序结果。