4

id、列parent、およびpath実体化されたパスである列があります。

のように見えます

1  | \N | 1  
2  | 1  | 1/2  
3  | 2  | 1/2/3  
4  | 3  | 1/2/3/4  
5  | 3  | 1/2/3/5  
6  | 2  | 1/2/6  
7  | 6  | 1/2/6/7  
8  | 2  | 1/2/8  
9  | 1  | 1/9  
10 | 9  | 1/9/10  
11 | 10 | 1/9/10/11  
12 | 11 | 1/9/10/11/12  
13 | 11 | 1/9/10/11/13  
14 | 11 | 1/9/10/11/14  
15 | 14 | 1/9/10/11/14/15  
16 | 14 | 1/9/10/11/14/16  
17 | 14 | 1/9/10/11/14/17  
18 | 10 | 1/9/10/18  
19 | \N | 19  
20 | 19 | 19\20  
21 | 19 | 19\21

このテーブルに基づいていくつかのクエリを実行する必要があります。

私がする必要があるクエリは


id9歳の子供をすべて選択

SELECT * FROM `tester` WHERE 'path' LIKE '%/9/%';  

最初にないのでIDを1または19に置き換えるまでは問題なく動作/します。

SELECT * FROM `tester` WHERE 'path' LIKE '%1/%';

番号が1で終わるすべての行を選択するため、1、11、21、31、211など

SELECT * FROM `tester` WHERE 'path' LIKE '1/%';

行1または19のいずれかで正しく機能します

だからSELECT * FROMテスターWHERE 'path' LIKE '1/%' OR 'path' LIKE '%/1/%';
私が思いつくことができる最高のものはありますか、何か提案はありますか?



このSelect * fromテスターの場合、9の直接の子を選択しますが、サブの子は選択しませんwhere 'parent' = 9。正常に動作します。


xレベルの深さの9の子の総数を選択します。

したがって、最終的に1行level1, level2, level3, ... levelxまたはx行のいずれかで、さまざまなレベルを表します。

この例では、xが3であると仮定します。この例の行は次のようになります9, 8, 6(要求した場合は4番目のレベルが3になります)

何か案は?

編集

#select count of children of specific node(5) down to a maximum of three levels, do no include the parent
SELECT COUNT(child.id) children, 
LENGTH(REPLACE(child.path, parent.path, '')) - LENGTH(REPLACE(REPLACE(child.path, parent.path, ''), '/', '')) AS LEVEL
FROM `tester` child JOIN `tester` parent ON child.path LIKE CONCAT(parent.path,'%') 
WHERE parent.id  =5 
GROUP BY LEVEL HAVING LEVEL <= 3 AND LEVEL > 0;


** 9の子IDをxレベルまで選択し、レベルは9を基準にします。

したがって、この例でも3をxとして使用します。

私たちは戻ってくることを探しています

10 | 1
11 | 2
18 | 2
12 | 3
13 | 3
14 | 3 

繰り返しますが、これを行う方法については完全に途方に暮れています。

編集:

#select all information, and relative level from parent of children of specific node(5) down to a maximum of three levels, do no include the parent
SELECT child.*, 
LENGTH(REPLACE(child.path, parent.path, '')) - LENGTH(REPLACE(REPLACE(child.path, parent.path, ''), '/', '')) AS LEVEL
FROM `tester` child JOIN `tester` parent ON child.path LIKE CONCAT(parent.path,'%') 
WHERE parent.id  =9 
GROUP BY id HAVING LEVEL <= 3 AND LEVEL > 0;
4

1 に答える 1

2

念のために言っておきますが、これらのソリューションは文字列の比較に基づいており、最適化されておらず、インデックスを使用できません。テーブルを別の方法で正規化することを検討する必要があります。(MySQLでの階層データの管理を参照してください)

いくつかの質問について:


ID9のすべての子を選択します。

Path列には先頭と末尾のスラッシュが含まれていないため、それらをパスに連結する必要があります。

SELECT * 
FROM tester
WHERE CONCAT('/', path, '/') LIKE '%/9/%';

9の子の総数を選択し、xレベルの深さ:

パス内のスラッシュの数から親パス内のスラッシュの数を引いたものでグループ化する必要があります。

SELECT (LENGTH(c.Path) - LENGTH(REPLACE(c.Path, '/', '')))
    - (LENGTH(p.Path) - LENGTH(REPLACE(p.Path, '/', ''))) AS Level,
    COUNT(*)
FROM tester c
    JOIN tester p ON c.Parent = p.ID
WHERE CONCAT('/', path, '/') LIKE '%/9/%';
GROUP BY 1

簡単にするために、上記のクエリを使用してすべてのレベルを表示しました。xレベルを深く制限する場合は、WHERE以下のクエリの述語を使用してください。


9の子IDをxレベルまで選択し、レベルは9を基準にします。

Path親のレベルを考慮しながら、レベルの斧数まで列を検索します。

SELECT c.*
FROM tester c
    JOIN tester p ON c.Parent = p.ID
WHERE CONCAT(
    '/',
    SUBSTRING_INDEX(
        Path, 
        '/', 
        (LENGTH(p.Path) - LENGTH(REPLACE(p.Path, '/', ''))) + 4
    ),
'/') LIKE '%/9/%'

私たちが取っているステップ:

  1. 親の深さを知る必要があります。親のパスのスラッシュを数えることでそれを見つけることができます。(LENGTH(p.Path) - LENGTH(REPLACE(p.Path, '/', ''))
  2. スラッシュが1つのパスは2レベルの深さであるため、その数に1を追加する必要があります。
  3. 必要なレベルのx個を追加します。
  4. レベル合計までパス列を取得します(SUBSTRING_INDEX関数を使用します)。
  5. 先頭と末尾のスラッシュを追加します。
  6. 最後の文字列で9を検索します。
于 2011-06-14T00:18:05.717 に答える