簡體   English   中英

將所有子代放入樹中的正確查詢是什么?

[英]What is the proper query to get all the children in a tree?

可以說我具有以下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中使用一個函數。 我認為對於像這樣的簡單事情,我們不需要完整的功能。

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

另外,請隨時更改結構。

您應該考慮將嵌套集用於此類數據結構

有關實現和用法的詳細信息,請參見http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

Mysql有一個很好的文章給你

介紹

大多數用戶一次或一次都在處理SQL數據庫中的層次結構數據,並且毫無疑問地了解到,層次結構數據的管理不是關系數據庫的目的。 關系數據庫的表不是分層的(如XML),而僅僅是一個平面列表。 層次結構數據具有父子關系,該父子關系在關系數據庫表中自然無法表示。

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

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

adf和bdc使四個節點與d“相鄰”,但是adc和bdf都不存在。 但是,關閉鄰接表將有效地假裝成他們這樣做。

因此,您的查詢確實確實需要類似“ ... WHERE ENDSWITH(domain,<parameter>)”。

您可能的問題是此查詢將始終需要全表掃描。

也許可以通過創建第二個表(domain1,domain2)解決此問題,該表僅表示“ domain1是domain2的子域”。 您可以使用在基表的每次更新上運行的觸發器或存儲庫來更新此表。 插入“ abcd”會在第二個表中插入三行:(abcd,bcd),(abcd,cd),(abcd,d)。

現在可以將查詢編寫為兩者之間的聯接,如果有適當的索引,該聯接將足夠快地運行。

編輯

但是這種方法存在嚴重的問題。 如果abcd被再次刪除,那么其他三行也應該刪除,除非當然仍然存在一些未刪除的xbcd行...

該解決方案很簡單,盡管在效率方面存在爭議。

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

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的混合語法,但是您明白了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM