2017-02-08 7 views
3

SQL - 次のように私はサンプルデータでは、次のMySQLのテーブルを持って再帰クエリ

id location   parentid 
1  UK     0 
2  East Anglia   1 
3  Cambridgeshire  2 
4  Norfolk    2 
5  Suffolk    2 
6  East Midlands  1 
7  Derbyshire   6 
8  Leicestershire  6 
9  EU Countries  0 
10 Austria    9 
11 Belgium    9 

私は場所の名前で場所のリストを取得することができますが、場所は任意の親を含むべきであることにより、クエリを生成したいですロケーション。例えば

folkの検索が返す必要があります:

id location 
4 Norfolk, East Anglia, UK 
5 Suffolk, East Anglia, UK 

Eastの検索が返す必要があります:

id location 
2 East Anglia, UK 
6 East Midlands, UK 

Belの検索は返す必要があります:上記の私たちには

id location 
11 Belgium 

を連結していないものを除きますEU countries

明らかに以下のdoesntの仕事:あなたはこれだけが自己で行われ、親の場所をしたい場合は

select c.id, CONCAT_WS(', ', c.location, p.location, pp.location) as location 
from tbl_locations c 
    outer left join tbl_locations p on p.id = c.parentid 
    outer left join tbl_locations pp on pp.id = p.parentid 
where c.location like '%whatever%' 
+1

あなたは与えられたlocationidのテキストを返す関数を作ることができます。編集:関数は呼び出す必要がなくなるまでそれ自身を呼び出す必要があります(再帰の定義でもあります) – Doruk

+0

http://guilhembichot.blogspot.co.uk/2013/11/with-recursive-and-mysql.html –

+0

最大深度? – sumit

答えて

3

参加:これは拡張することができます

select c.id, c.location, p.id, p.location 
from tbl_locations c 
    outer left join tbl_locations p on p.id = c.parentid 
where c.location like '%whatever%' 

(外部結合を経由して)任意の数のレベルに設定できますが、クエリは長くなります。例えば。

select c.id, c.location, p.id, p.location, pp.id, pp.location 
from tbl_locations c 
    outer left join tbl_locations p on p.id = c.parentid 
    outer left join tbl_locations pp on pp.id = p.parentid 
where c.location like '%whatever%' 

さらに一般的な再帰クエリは、RDBMSの詳細によって異なります。最も簡単な方法は、Common Table Expression(CTE)を使用する方法です。しかし、MySQLはそれらをサポートしていません(少なくとも、まだ)。他の方法を使用することができる:Generating Depth based tree from Hierarchical Data in MySQL (no CTEs)

+0

私は4つのレベルを持っていると言うことができますが、上記のパフォーマンスに大きな影響がありますか? – adam78

+0

@ adam78:いつものように、現実的なデータセットで測定する必要があります。詳細なレベル(何千もの行)のすべての英国の場所で、「id」と「parentid」を索引付けしても、私はそれがかなり速くなると期待します。しかし、確実な唯一の方法は、現実的なデータでテストし、そのようなクエリをどのくらい頻繁に使用するかを検討することです。 – Richard

1

1) "推移閉包"推移関係を計算できる標準的なSQLクエリーはありません。選択ステートメントをネストする場合は、常に最大深度に達することができます。

2)可変数の列を持つ行を返す標準SQLクエリはありません。したがって、結果を何らかの形でフォーマットする必要があります(例:csv)。

ただし、ストアドプロシージャを使用してMySQLにそれを達成することができます

1 CREATE DATABASE IF NOT EXISTS test; 
2 USE test; 
3 
4 
5 DROP TABLE IF EXISTS location; 
6 CREATE TABLE location (id INT UNSIGNED PRIMARY KEY, name VARCHAR(30) NOT NULL, parent_id INT UNSIGNED NULL REFERENCES location(id)); 
7 
8 INSERT INTO location VALUES 
9 (1,"UK",0), 
10 (2,"East Anglia",1), 
11 (3,"Cambridgeshire",2), 
12 (4,"Norfolk",2), 
13 (5,"Suffolk",2), 
14 (6,"East Midlands",1), 
15 (7,"Derbyshire",6), 
16 (8,"Leicestershire",6); 
17 
18 
19 
20 
21 DROP FUNCTION IF EXISTS location_with_parents; 
22 DELIMITER // 
23 CREATE FUNCTION location_with_parents(location_id INT UNSIGNED) RETURNS VARCHAR(255) READS SQL DATA 
24 BEGIN 
25  DECLARE LOC_STR VARCHAR(255) DEFAULT NULL; 
26  DECLARE LOC_ADD VARCHAR(255) DEFAULT NULL; 
27  DECLARE PAR_ID INT UNSIGNED DEFAULT location_id; 
28  
29  SELECT name INTO LOC_STR FROM location where id=PAR_ID; 
30  loop_label: LOOP 
31   SELECT parent_id INTO PAR_ID FROM location where id=PAR_ID; 
32   
33   IF PAR_ID = 0 THEN 
34    LEAVE loop_label; 
35   ELSE 
36    SELECT name INTO LOC_ADD FROM location where id=PAR_ID; 
37    SET LOC_STR = CONCAT(LOC_STR, ', ', LOC_ADD); 
38    ITERATE loop_label; 
39   END IF; 
40  END LOOP loop_label; 
41  RETURN LOC_STR; 
42  
43 END; 
44 // 
45 
46 DELIMITER ; 
47 
48 
49 
50 SELECT location_with_parents(id) FROM location WHERE name LIKE "%folk%"; 
51 
52 DROP DATABASE test; 

作品を私のためにこの情報がお役に立てば幸いです

のMySQL 5.6.35で!

1

以下のクエリは、再帰メソッドを使用したい正確な結果を提供します。

Select S.ID , 
    concat(S.location,',', Group_concat 
    (distinct A.location ORDER BY A.location SEPARATOR ',')) as location 
    from 

     ( SELECT distinct @r AS _id ,location, 
         (
         SELECT @r := parentid 
         FROM tbl_locations 
         WHERE id = _id 
         ) AS parentid, 
         @l := @l + 1 AS level 
       FROM (
         SELECT @r := h.ID, 
           @l := 0, 
           @cl := 0 
         from tbl_locations h 
         where location like '%folk%' 

         ) vars, 
         tbl_locations h 
       WHERE @r <> 0 


     )A , tbl_locations S 
       where s.location like '%folk%' 
       group by S.ID 

出力:

location like '%East%' : 

enter image description here

location like '%Folk%' 

enter image description here

その良い質問と確認し、任意の懸念を持っているかどうか尋ねます。

+0

@ adam78これをチェックしましたか?その仕事かどうか? –

関連する問題