2010-03-25 22 views
1

可以說我有以下MySQL的結構:什麼是正確的查詢來獲得樹中的所有孩子?

CREATE TABLE `domains` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
`domain` CHAR(50) NOT NULL, 
`parent` INT(11) DEFAULT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=MYISAM AUTO_INCREMENT=10 DEFAULT CHARSET=latin1 

insert into `domains`(`id`,`domain`,`parent`) values (1,'.com',0); 
insert into `domains`(`id`,`domain`,`parent`) values (2,'example.com',1); 
insert into `domains`(`id`,`domain`,`parent`) values (3,'sub1.example.com',2); 
insert into `domains`(`id`,`domain`,`parent`) values (4,'sub2.example.com',2); 
insert into `domains`(`id`,`domain`,`parent`) values (5,'s1.sub1.example.com',3); 
insert into `domains`(`id`,`domain`,`parent`) values (6,'s2.sub1.example.com',3); 
insert into `domains`(`id`,`domain`,`parent`) values (7,'sx1.s1.sub1.example.com',5); 
insert into `domains`(`id`,`domain`,`parent`) values (8,'sx2.s2.sub1.example.com',6); 
insert into `domains`(`id`,`domain`,`parent`) values (9,'x.sub2.example.com',4); 

在我的腦海裏,就足以模擬一個簡單的樹形結構:

  .com 
      |    
      example     
     /  \ 
     sub1   sub2 

ECT

我的問題是給SUB1。 example.com我想知道sub1.example.com的所有子代,而不使用我的代碼中的多個查詢。

我已經嘗試加入表本身,並試圖使用子查詢,我想不出任何會揭示所有的孩子。

在工作中,我們正在使用MPTT保持域名/子域名列表的順序,但我覺得有一個更簡單的方法來做到這一點。

我做了一些挖掘,有人做了類似的事情,但他們需要使用MySQL中的函數。我不認爲像這樣簡單,我們需要一個完整的功能。

也許我只是愚蠢的,沒有看到某種明顯的解決方案。

此外,請隨時更改結構。

+2

'SELECT * FROM TREEHOUSE'是我第一次猜測。 – 2010-03-25 19:50:35

回答

0

解決方法很簡單,儘管它的效率有爭議。

我已經修改了表結構,如下所示:

CREATE TABLE `domains` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
    `domain` CHAR(50) NOT NULL, 
    `level` INT(11) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=MYISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 

等級涉及在樹中的深度。

的樣本數據:

insert into `domains`(`id`,`domain`,`level`) values (1,'.com',0); 
insert into `domains`(`id`,`domain`,`level`) values (2,'example.com',1); 
insert into `domains`(`id`,`domain`,`level`) values (3,'sub1.example.com',2); 
insert into `domains`(`id`,`domain`,`level`) values (4,'sub2.example.com',2); 
insert into `domains`(`id`,`domain`,`level`) values (5,'s1.sub1.example.com',3); 
insert into `domains`(`id`,`domain`,`level`) values (6,'s2.sub1.example.com',3); 
insert into `domains`(`id`,`domain`,`level`) values (7,'sx1.s1.sub1.example.com',4); 
insert into `domains`(`id`,`domain`,`level`) values (8,'sx2.s2.sub1.example.com',4); 
insert into `domains`(`id`,`domain`,`level`) values (9,'x.sub2.example.com',3); 
insert into `domains`(`id`,`domain`,`level`) values (10,'t.sx1.s1.sub1.example.com',5); 

因此,可以說,我們給出sub1.domain.com,我們想知道所有的子查詢是相當簡單:

SELECT * FROM domains WHERE domain LIKE "%.sub1.example.com" ORDER BY level; 

當然,如果我們希望sub1.example.com在我們的結果集,我們可以這樣做:

SELECT * FROM domains WHERE domain LIKE "%sub1.example.com" ORDER BY level; 

從結果集,我們得到的名單讓孩子們生孩子。

要刪除一個孩子(和所有相關兒童)很簡單,一個非常類似的查詢

DELETE FROM domains WHERE domain LIKE "%sub1.example.com"; 

的插入容易,它只是需要2個查詢(假設用戶有一個下拉框,並選擇父母):

SELECT level FROM domains WHERE domain = "sub2.example.com"; 

INSERT INTO domains (domain, level) VALUES ($sub + ".sub2.example.com", $level+1) 

請原諒混合的PHP + MySQL語法,但您明白了。

1

Mysql的細節有a good article for you

介紹

在一個

大多數用戶時間或其他已經處理了SQL數據庫中的分層數據,並且毫無疑問地知道了hi的管理層次數據不是關係數據庫的目標。關係數據庫的表不是分層的(比如XML),而只是一個簡單的列表。分層數據具有在關係數據庫表中不自然表示的父子關係。

出於我們的目的,分層數據是一個數據集合,其中每個項目具有單個父項和零個或多個子項(除了沒有父項的根項目)。可以在各種數據庫應用程序中找到分層數據,包括論壇和郵件列表線程,業務組織結構圖,內容管理類別和產品類別。對於我們的目的,我們將使用虛構電子商店中的以下產品類別層次結構:

0

鄰接列表只會幫助您獲得錯誤的結果。

a.d.f和b.d.c使四個節點「與d相鄰」,但a.d.c和b.d.f都不存在。但是,關閉鄰居名單會有效地假裝他們會這樣做。

所以您的查詢確實需要像」 ... WHERE的endsWith(域,<參數>)。

你可能的問題是,這個查詢將始終需要全表掃描。

也許這可以通過創建第二個表(domain1,domain2)來解決,該表僅表示「domain1是domain2的子域」。您可以使用在基表的每個更新上運行的觸發器或sprocs更新此表。 「a.b.c.d」的插入在第二個表中插入三行:(a.b.c.d,b.c.d),(a.b.c.d,c.d),(a.b.c.d,d)。

您的查詢現在可以寫成兩個,這將運行速度不夠快,如果適當的索引是在地方之間的聯接。

編輯

但是這樣的方法存在嚴重的問題。如果再次刪除a.b.c.d,那麼其他三行也應該刪除,除非當然還有一些未刪除的x.b.c.d行...

相關問題