根据前身订购SQL结果

时间:2011-06-09 18:38:09

标签: sql informix

我的数据库中有以下表格:

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

我想要一个选择namevalue的SQL查询,这个查询是有序的,因此具有前驱null的项是第一个,然后是谁的前任的行等于该行的名字是下一个等等(即购买者,搅拌者,做饭,吃饭)。

排序是严格线性的 - 如果两行具有相同的前导值,则行为是未定义的。

我正在努力寻找能够产生我想要的排序的SQL查询。我真的不知道从哪里开始。

我正在使用Informix数据库,但SQL的任何变体都是一个有用的起点。

已更新,以反映排序不按字母顺序

的事实

4 个答案:

答案 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)

我认为做你想做的事情的方法是为每个项目构建一个带有“深度”字段的临时表,然后使用该深度字段来排序结果。