2012-10-23 24 views
3

在我的系統中,每個項目都有一些標籤。現在我想向用戶展示一個帶有標籤的樹。 樹應該有第一級的所有標籤。
在每個第一級標籤內,應再次出現在屬於第一級標籤的項目中找到的所有標籤。
在第三級中,應該出現屬於第一級和第二級的標籤,依此類推。
這個想法是,用戶可以基於他的標籤過濾項目,並且可以改進輸入到樹中的過濾而不必鍵入標籤。如何讓SQL根據具有相同標籤的項目創建標籤層次結構?

項目最初作爲項目表中的字符串字段存儲,但爲了輕鬆製作此解決方案,我已將它們移動到子表中。

使用這些物品作爲輸入:

|Item  |Tags | 
|-----------|--------| 
|Computer |a,b,c | 
|Mouse  |a,c  | 
|Keyboard |c,d  | 
|Monitor |a,b  | 

應該輸出樹:

Tree    Items that are show when selected 

    root    Computer,Mouse,Keyboard,Monitor 
    +--a   Computer,Mouse,Monitor 
    | +--b  Computer,Monitor 
    | | +--c  Computer 
    | +--c  Computer,Mouse 
    |  +--b  Computer 
    +--b   Computer,Monitor 
    | +--a  Computer,Monitor 
    | | +--c  Computer 
    | +--c  Computer 
    |  +--a  Computer 
    +--c   Computer,Mouse,Keyboard 
    | +--a  Computer,Mouse 
    | | +--b  Computer 
    | +--b  Computer 
    | | +--a  Computer 
    | +--d  Keyboard 
    +--d   Keyboard 
     +--c  Keyboard 

這SQL應該運行只在Oracle數據庫中,所以使用connect by運營商是可以接受的。

我從Delicious的Firefox擴展中選擇了這種行爲,它以樹的形式顯示標籤,但限制它只有兩個級別,我需要它顯示儘可能多的級別。

你有什麼想法嗎?

在此先感謝。

+0

順便說一句:在4個實體上有4個標籤,您的樹視圖中有19行。有了大量的標籤和/或實體,這將爆炸成不可能管理的數字。 – MatBailie

+0

對。但是我不會有大量的標籤,最多50個標籤,只有當標籤被選中時我纔會加載這些標籤,所以我認爲這不是問題。但是,感謝評論。 –

回答

0

[PLZ,原諒我的SQL Server語法......我的Oracle技能生疏和我手頭沒有服務器]

在我兩次遇到這個問題在過去的十年!

我的解決辦法:

  1. 設計的單表遞歸關係

    CREATE TABLE dummy(
        id  VARCHAR(128) NOT NULL, 
        parent_id VARCHAR(128) NULL, 
        -- 
        CONSTRAINT pk_dummy PRIMARY KEY(id), 
        -- 
        CONSTRAINT fk_dummy_X_dummy 
        FOREIGN KEY(id) REFERENCES dummy(id) 
    ) 
    
  2. 設計預先計算層次結構中的非規範化表:

    CREATE TABLE dummy_hierarchy(
        id  VARCHAR(128) NOT NULL, 
        parent_id VARCHAR(128) NOT NULL, 
        depth  INT NOT NULL 
    ) 
    

    dummy_hierarchy有性能:

    • id具有「1」
    • iddepth值的自相關具有「2」
    • iddepth值蒙山其父的關係具有與其宏偉母體與「depth值之間的關係3'
    • 等等...

    另外:

    • id一個檢索所有的前輩,包括id本身
    • parent_id一個檢索所有的繼任者,包括parent_id本身
  3. dummy定義一個觸發器,應保持dummy_hierarchy最新:

    CREATE TRIGGER tr_dummy_ins_upd_del 
    ON dbo.dummy FOR INSERT, UPDATE, DELETE 
    AS 
    BEGIN 
        DELETE dummy 
        FROM DELETED 
        WHERE dummy.id = DELETED.id 
    
        INSERT INTO dbo.dummy_hierarchy(
        id, parent_id, depth 
    ) 
        SELECT id, id, 1 
        FROM INSERTED 
    
        WHILE 1 = 1 
        BEGIN 
        INSERT INTO dbo.dummy_hierarchy(
         id, parent_id, depth 
        ) 
        SELECT hie.id, par.parent_id, hie.depth + 1 
        FROM 
         INSERTED ins 
         INNER JOIN(
          dbo.dummy_hierarchy hie 
          INNER JOIN dummy par 
          ON par.id = hie.parent_id 
         ) 
         ON hie.id = ins.id 
        WHERE par.parent_id IS NOT NULL 
         -- 
         AND NOT EXISTS(
          SELECT id 
          FROM dummy_hierarchy hie_par 
          WHERE hie_par.id  = hie.id 
           AND hie_par.parent_id = par.parent_id 
         ) 
    
        IF @@ROWCOUNT = 0 
        BEGIN 
         BREAK 
        END 
        END 
    END 
    

    作爲POC數據:

    INSERT INTO dummy(id, parent_id) VALUES('COMPUTER', NULL) 
    INSERT INTO dummy(id, parent_id) VALUES('MONITOR', 'COMPUTER') 
    INSERT INTO dummy(id, parent_id) VALUES('MOUSE', 'MONITOR') 
    INSERT INTO dummy(id, parent_id) VALUES('KEYBOARD', 'MONITOR') 
    

    查詢:

    SELECT * 
    FROM dbo.dummy_hierarchy hie 
    WHERE parent_id = 'COMPUTER' 
    

    Yelds:

     
        id  parent_iddepth 
        COMPUTER COMPUTER 1 
        MONITOR COMPUTER 2 
        MOUSE  COMPUTER 3 
        KEYBOARD COMPUTER 3 
    

    這一個:

    SELECT * 
    FROM dbo.dummy_hierarchy hie 
    WHERE parent_id = 'MONITOR' 
    

    Yelds:

     
        id  parent_iddepth 
        MONITOR MONITOR 1 
        MOUSE  MONITOR 2 
        KEYBOARD MONITOR 2 
    

    而且,對於反跟蹤:

    SELECT * 
    FROM dbo.dummy_hierarchy 
    WHERE id = 'MOUSE' 
    

    有:

     
        id  parent_iddepth 
        MOUSE  MOUSE  1 
        MOUSE  MONITOR 2 
        MOUSE  COMPUTER 3 
    

    當然,這不正是你所需要的。

    但我想提供一些有用的線索。

相關問題