2013-04-22 120 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