24

次のテーブルがあるとします。

CustomerID ParentID Name
========== ======== ====
1          null     John
2          1        James
3          2        Jenna
4          3        Jennifer
5          3        Peter
6          5        Alice
7          5        Steve
8          1        Larry 

James のすべての子孫 (Jenna、Jennifer、Peter、Alice、Steve) を 1 つのクエリで取得したいと考えています。ありがとう、パブロ。

4

4 に答える 4

34

SQL Server 2005 では、 CTE (Common Table Expressions)を使用できます。

with Hierachy(CustomerID, ParentID, Name, Level)
as
(
select CustomerID, ParentID, Name, 0 as Level
    from Customers c
    where c.CustomerID = 2 -- insert parameter here
    union all
    select c.CustomerID, c.ParentID, c.Name, ch.Level + 1
    from Customers c
    inner join Hierachy ch
    on c.ParentId = ch.CustomerID
)
select CustomerID, ParentID, Name
from Hierachy
where Level > 0
于 2008-10-27T08:01:03.240 に答える
3

ボトムアップの場合は、少し変更を加えてmathieuの回答を使用します。



with Hierachy(CustomerID, ParentID, Name, Level)
as
(
select CustomerID, ParentID, Name, 0 as Level
    from Customers c
    where c.CustomerID = 2 -- insert parameter here
    union all
    select c.CustomerID, c.ParentID, c.Name, ch.Level + 1
    from Customers c
    inner join Hierachy ch

    -- EDITED HERE --
    on ch.ParentId = c.CustomerID
    ----------------- 

)
select CustomerID, ParentID, Name
from Hierachy
where Level > 0


于 2010-09-25T13:28:29.457 に答える
0

ストアド プロシージャがなければ、SQL で再帰を行うことはできません。これを解決する方法は、ネストされたセットを使用することです。基本的に、SQL のツリーをセットとしてモデル化します。

これには、現在のデータ モデルを変更するか、元のモデルでビューを作成する方法を考え出す必要があることに注意してください。

Postgresql の例 (非常に少数の postgresql 拡張機能を使用し、SERIAL と ON COMMIT DROP だけを使用すると、ほとんどの RDBMS は同様の機能を持ちます):

設定:

CREATE TABLE objects(
    id SERIAL PRIMARY KEY,
    name TEXT,
    lft INT,
    rgt INT
);

INSERT INTO objects(name, lft, rgt) VALUES('The root of the tree', 1, 2);

子の追加:

START TRANSACTION;

-- postgresql doesn't support variables so we create a temporary table that 
-- gets deleted after the transaction has finished.

CREATE TEMP TABLE left_tmp(
    lft INT
) ON COMMIT DROP; -- not standard sql

-- store the left of the parent for later use
INSERT INTO left_tmp (lft) VALUES((SELECT lft FROM objects WHERE name = 'The parent of the newly inserted node'));

-- move all the children already in the set to the right
-- to make room for the new child
UPDATE objects SET rgt = rgt + 2 WHERE rgt > (SELECT lft FROM left_tmp LIMIT 1);
UPDATE objects SET lft = lft + 2 WHERE lft > (SELECT lft FROM left_tmp LIMIT 1);

-- insert the new child
INSERT INTO objects(name, lft, rgt) VALUES(
    'The name of the newly inserted node', 
    (SELECT lft + 1 FROM left_tmp LIMIT 1), 
    (SELECT lft + 2 FROM left_tmp LIMIT 1)
);

COMMIT;

下から上にトレイルを表示します。

SELECT
    parent.id, parent.lft
FROM
    objects AS current_node
INNER JOIN
    objects AS parent
ON
    current_node.lft BETWEEN parent.lft AND parent.rgt
WHERE
    current_node.name = 'The name of the deepest child'
ORDER BY
    parent.lft;

ツリー全体を表示します。

SELECT
    REPEAT('   ', CAST((COUNT(parent.id) - 1) AS INT)) || '- ' || current_node.name AS indented_name
FROM
    objects current_node
INNER JOIN
    objects parent
ON
    current_node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY
    current_node.name,
    current_node.lft
ORDER BY
    current_node.lft;

ツリーの特定の要素からすべてを選択します。

SELECT
    current_node.name AS node_name
FROM
    objects current_node
INNER JOIN
    objects parent
ON
    current_node.lft BETWEEN parent.lft AND parent.rgt
AND
    parent.name = 'child'
GROUP BY
    current_node.name,
    current_node.lft
ORDER BY
    current_node.lft;
于 2008-10-27T07:44:23.320 に答える
-9

私が何かを見逃していない限り、再帰は必要ありません...

SELECT d.NAME FROM Customers As d
INNER JOIN Customers As p ON p.CustomerID = d.ParentID
WHERE p.Name = 'James'
于 2008-10-27T18:13:27.030 に答える