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');

还有另一个表,我保留 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”。如果青苹果下有标记为继承 = 'Y' 的子类别......例如“一打青苹果”也应该列出!!

我想试一试 UNION,但不知道如何让 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

3 回答 3

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;
    }

}

所以假设苹果的分类是继承的,结果getCategory(1)应该是Fruits,Apples,Green Apples

于 2013-04-22T12:04:13.020 回答
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 的类别 ID 的完整列表。

CALL show_user_categories( 1000 ); 

请参阅sqlfiddle的工作示例。

于 2013-04-23T06:47:54.927 回答
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
于 2013-04-22T12:08:41.797 回答