2013-04-22 66 views
2

我有這個數據庫表與父子關係類別數據

CREATE TABLE IF NOT EXISTS `category` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `parent_id` int(11) NOT NULL, 
    `name` varchar(100) NOT NULL, 
    `inherit` enum('Y','N') NOT NULL DEFAULT 'N', 
    PRIMARY KEY (`id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=15 ; 

-- 
-- Dumping data for table `category` 
-- 

INSERT INTO `category` (`id`, `parent_id`, `name`, `inherit`) VALUES 
(1, 0, 'Fruits', 'N'), 
(2, 0, 'Electronics', 'N'), 
(3, 0, 'Furniture', 'N'), 
(4, 0, 'Garden', 'N'), 
(5, 1, 'Apples', 'N'), 
(6, 1, 'Bananas', 'N'), 
(7, 5, 'Green Apples', 'Y'), 
(8, 5, 'Red Apples', 'N'), 
(9, 2, 'Mobiles', 'Y'), 
(10, 2, 'Televisions', 'N'), 
(11, 9, 'Android', 'N'), 
(12, 9, 'iPhone', 'Y'), 
(13, 7, 'One Dozen Green Apples', 'Y'), 
(14, 7, 'Two Dozens Green Apples', 'N'); 

select查詢還有一個表,其中我一直USER_ID,例如CATEGORY_ID USER_ID 1000可以看到1和5,我把這個信息的會議讓我的查詢變得

SELECT * 
FROM `category` 
WHERE id 
IN (1, 5) 

這個查詢顯示Fruits > Apples - 這一切工作正常。但是,我將「Green Apples」標記爲Inherit = 'Yes',因此用戶1000也應該看到「Green Apples」,但不是「Red Apples」。如果青蘋果下的子類別標記爲inherit ='Y'... 「一打青蘋果」也應該列出來!

我想給UNION一去,但無法弄清楚如何獲得超過2級更深...

SELECT * FROM (
    SELECT * 
    FROM `category` 
    WHERE id 
    IN (1, 5) 

    UNION 

    SELECT c.* 
    FROM `category` c 
    INNER JOIN `category` parent ON parent.id = c.id AND c.inherit = 'Y' 
    WHERE c.parent_id 
    IN (1, 5) 
) all_cats 

,你會建議我什麼?如果可以更輕鬆地查詢,我是否打開了表格結構更改?感謝

回答

4

嘗試自聯接:

編輯:我忘了WHERE子句

SELECT 
    a.name, 
    b.name, 
    c.name 
FROM 
    category as a 
LEFT JOIN category as b 
    ON b.parent_id = a.id 
INNER JOIN category as c 
    ON c.parent_id = b.id 
    AND c.inherit = 'Y' 
WHERE 
    a.id = 1 

但理想的解決方案是有一個遞歸函數,將在該表中做到這一點,因爲你正在描述一個類別樹。上面的查詢是靜態的,它返回2個級別(2個子類別),從我的理解你需要動態的東西。

類似下面的功能:

public String getCategory(int categId){ 

    String sSql = "SELECT name FROM category WHERE id = " + categId ; 
    String name = oDb.exec(sql).get("name"); 

    sSql = "SELECT id FROM category WHERE inherit = 'Y' AND parent_id = " + categId ; 
    int nextCategId = oDb.exec(sql).get("id"); 

    if(nextCategId != null){ 
     return name + "," + getCategory(nextCategId); 
    }else{ 
     return name; 
    } 

} 

所以假設蘋果CATEG繼承了getCategory(1)結果應該是Fruits,Apples,Green Apples

+0

是的,我明白你的意思。其實,上面的1&5是通過這樣的功能選擇的。例如,User_Category表只有5個,但我通過上面的類似函數選擇它的父項1。我只是想知道如果我可以用查詢來實現...如果沒有,我需要再次檢查該函數,看看如何獲​​得繼承= Y的 – user1421214 2013-04-22 12:21:52

+0

你不能通過查詢實現這一點,由於簡單的事實,你不從一開始就知道一個類別有多少個子級別......但是如果你存儲了這個信息(categ_id |子級別的數量),你可以動態地生成一個類似於上面的查詢(聯接數目=子級別數目) – Stephan 2013-04-22 12:28:21

+0

yes是正確的我不知道在一開始的水平...但是,我可以修改腳本,以保持水平.... – user1421214 2013-04-22 12:30:17

0

在SQL Server:

;with CTE as 
(
select id,name from category where id in(1,5) 
union all 
select c.id,c.name from category c join CTE ct on c.parent_id=ct.id and c.inherit='Y' 
) 


select * from CTE 
+0

我已經試過了。但是綠蘋果的孩子類別呢? – user1421214 2013-04-22 12:11:01

+0

試試這個更新的解決方案 – AnandPhadke 2013-04-22 12:22:29

+0

我已經更新了上面的表格(添加了綠色蘋果的兩個子類別...其中一個繼承= y其他沒有)上述查詢不提取「一打青蘋果 – user1421214 2013-04-22 12:26:01

1

要獲得所有類別在mysql中的一個查詢中,您將需要儘可能多的自聯接,因爲您的類別樹中存在深度級別。 如果您的深度水平不受限制,這顯然是不可能的。 但是,您可以使用存儲過程來執行id。

假設你有一個類別的表像用戶:

CREATE TABLE IF NOT EXISTS `user_category` (
    `user_id` int(11) NOT NULL, 
    `category_id` int(11) NOT NULL, 
    PRIMARY KEY (`user_id`,`category_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

與像一些數據:

INSERT INTO `user_category` (`user_id`, `category_id`) VALUES 
(1000, 1), 
(1000, 5); 

您可以創建臨時表cat_tree存儲類別的ID的,與初始化所有來自user_category表的給定user_id的父類別,並且只要最後一次連接插入至少一個尚未存在的類別,就重複自下而上的連接。

DELIMITER // 
DROP PROCEDURE IF EXISTS show_user_categories// 
CREATE PROCEDURE show_user_categories(uid INT(11)) 
BEGIN 
    DECLARE found INT(11) DEFAULT 1; 
    DROP TABLE IF EXISTS cat_tree; 
    CREATE TABLE cat_tree (cat_id int(11) PRIMARY KEY) ENGINE=HEAP; 
    INSERT INTO cat_tree 
    SELECT category_id FROM user_category 
    WHERE user_id = uid; 
    SET found = ROW_COUNT(); 
    WHILE found > 0 DO 
    INSERT IGNORE INTO cat_tree 
     SELECT c_child.id FROM cat_tree c JOIN category c_child 
     WHERE c.cat_id = c_child.parent_id AND c_child.inherit = 'Y'; 
    SET found = ROW_COUNT(); 
    END WHILE; 
    SELECT cat_id FROM cat_tree; 
    DROP TABLE cat_tree; 
END;// 
DELIMITER ; 

此過程爲您提供給定user_id的類別標識的完整列表。

CALL show_user_categories(1000); 

查看sqlfiddle的工作示例。

+0

我已經設法實現類似的邏輯(這是在程序中)使用PHP。+1的答案,但我有限的經驗,程序..會這樣工作,例如$ sql =「程序這裏」; $ db->查詢($ sql);? – user1421214 2013-04-23 15:13:18

+0

是的,它可以工作,唯一的問題可能是你的mysql用戶沒有權限運行SP,嘗試比較php和mysql解決方案,mysql應該更快,因爲不需要發送所有數據。 – piotrm 2013-04-23 18:51:22