3

現在有一個問題,我們通常使用這種技術來維護父子關係,即我們將所有實體存儲在一個表中,其中parent_id列爲parent_id列,所有最頂級父母都有這是一個很好的和規範化技術我同意,但也有一個缺點,它是緩慢和低效率。這主要是由於像每個家長,我們必須再次運行查詢,並再次作出樹通過第n個孩子ID獲得最頂級的父母?

SELECT id FROM `table` WHERE parent_id=something 

我已經看過了解決方案,通過運行查詢的一些可能會嘗試與任何編程語言做遞歸一次又一次地在服務器上產生負載,一些提供了存儲過程,但也涉及遞歸。

所以我的問題是我們可以用一個數據庫查詢樹(連接或子查詢)嗎?

  • 如果我們知道深度還是我們不知道深度?
  • 如果有可能,我們如何獲得任何孩子的最頂級父母(即parent_id = 0)?
  • 如果這是不可能的,那麼爲什麼這種技術是如此着名,雖然它有缺陷,或者我們有另一種解決方案呢?

    我已經加入了SQL小提琴,但它只有架構

FIDDLE

+3

不像一些其他的RDBMS,MySQL不支持遞歸函數等是不適合這是存儲分層數據的「鄰接表」模型。您應該考慮重新構建您的模式以將分層結構嵌入到MySQL可以利用的表單中,例如「嵌套集合」或「傳遞閉包」。 – eggyal

+0

@eggyal但現在很多cms都遵循這種技術,像最常用的wordpress也提供了第n個菜單級別,頁面級別和類別級別,所以我的問題是有沒有更好的方式來存儲和獲取樹,而無需運行多個查詢? –

+0

您可以爲您希望獲取的每一代自行加入,但深度總是受限於查詢中的連接數。 – eggyal

回答

3

我不知道是否有可能與MYSQL,我一直在工作主要是與SQL Server在我的職業生涯。在SQL Server中,可以通過使用WITH語句只用1個查詢來完成。

這演示瞭如何在各級

With pa as (
    select pa1.* 
    From prarent as pa1 
    Where id = 3 
    union all 
    select pa2.* 
    from pa join prarent as pa2 on pa.id = pa2.parent_id 
) 
select * from pa where pa.id != 3 

DEMO

又如得到一個對象(ID = 3)的所有兒童得到一個對象的所有家長(ID = 7)至最上面的

With pa as (
    select pa1.* 
    From prarent as pa1 
    Where id = 7 
    union all 
    select pa2.* 
    from pa join prarent as pa2 on pa.parent_id = pa2.id 
) 
select * from pa where pa.id != 7 

DEMO

Anothe R實施例,僅保留最頂層父

With pa as (
    select pa1.* 
    From prarent as pa1 
    Where id = 7 
    union all 
    select pa2.* 
    from pa join prarent as pa2 on pa.parent_id = pa2.id 
) 
select top 1 * 
from pa 
where pa.id != 7 
order by id asc 

在這個例子中,我假設ID是增量和我用一個簡單的方法(只用於演示目的)使用order by以獲得最頂層。您可以根據數據庫設計使用其他技術。

DEMO

使用這種類似的技術,你可以做更多,喜歡把自己的最底部孩子,....

+0

非常感謝你,如果你知道這種功能可能在MySQL中,那麼請編輯這個答案,這裏是你的獎勵:) –

+0

@dianuj:非常感謝你 –

0

如果你有很多的層次,或者大量數據,這將是不切實際的。

否則,您可以嘗試模擬遞歸函數的功能。即使你不會得到相同的表現,如果你沒有太多的數據,也沒有太多的水平,這並不重要。

的一般過程是如下:

  1. 對於給定的父母,與選擇記錄與ID
  2. 此外,選擇記錄作爲PARENT_ID,和UNION這與以前
  3. 步驟#2中的子查詢給出了一級子元素,因此您可以編寫一個查詢來選擇它們的ID,並將其用作第三個查詢中的子選擇,該子查詢指出「where PARENT_ID IN(sub-select) 「
  4. 這將類似於步驟#3,並繼續這樣做

它看起來是這樣的:(see the Fiddle here

select * 
from prarent P0 
where id = 3 

union 

select * 
from prarent P1 
where parent_id = 3 

union 

select * 
from prarent P2 
where parent_id in 
( select distinct id 
    from prarent P1 
    where p1.parent_id = 3 
) 

union 

select * 
from prarent P3 
where parent_id in 
( select distinct id 
    from prarent P2 
    where parent_id in 
    ( select distinct id 
     from prarent P1 
     where p1.parent_id = 3 
    ) 
) 
+0

如果你看到你有深度1聯合查詢與sub選擇,你已經在你的答案中提到**如果你有很多的水平,或大量的數據,這將是不切實際的**我想要一個通用的如果不是,那麼爲什麼這種方法如此受歡迎? –

+0

如果邏輯結構是一棵樹,那麼很少有替代品仍然是靈活的。實際上,當我使用「BOM」結構時,用例就是這樣一個用例,它關注於一定的層次,並在需要時進行深入研究。所以,實際上,即使數據庫沒有提供容易遞歸的SQL,我也可能保持這種結構。如果您有能力將SQL與某些3-G代碼混合使用(即使它存儲在存儲過程中),但在大多數情況下,性能並不是很重要的問題。編碼麻煩,但不是性能問題。 –

相關問題