按顺序显示类别和子类别

时间:2013-06-29 17:40:51

标签: mysql sql

在创建SQL查询以显示一个表中的类别和子类别时,我遇到了很多麻烦。我有以下专栏:

category_id
category_name
category_parent
category_order

基本上我想要产生的结果是这样的

parent category 1
sub category 1
sub category 2
parent category 2
sub category 1
sub category 2
sub category 3
parent category 3
sub category 1

如果category_order设置为0,则应根据创建的顺序对类别或子类别进行排序。为此我打算按ID排序。

如果可能的话我想使用UNION,以便它们已经按顺序排列,我只需要循环。任何人都可以帮我建立一个查询。

实际上我已经有一个使用JOIN,但结果并不像我想要的那样精确。

这是我之前的查询:

SELECT
fcat.id fcat_id,
fcat.name fcat_name,
fcat.order fcat_order,
fcat.parent fcat_parent,
fsub.id fsub_id,
fsub.name fsub_name,
fsub.order fsub_order,
fsub.parent fsub_parent
FROM forum_categories AS fcat
LEFT OUTER JOIN forum_categories AS fsub ON fcat.id = fsub.parent
ORDER BY ISNULL(fcat.order) ASC, fcat.id ASC, ISNULL(fsub.order) ASC, fsub.id ASC

但是,它不对子类别进行排序,因为父类别和子类别已连接。我的查询只对父母进行排序。

6 个答案:

答案 0 :(得分:4)

我认为排序是这里有趣的部分。特别是,类别中的排序很有趣。我做了一个小提琴,说明了这一点:http://sqlfiddle.com/#!8/78059/3

以下是查询:

select * from (
  select c.*,
  coalesce(nullif(c.parent, 0), c.id) as groupID,
  case when c.parent = 0 then 1 else 0 end as isparent,
  case when p.`order` = 0 then c.id end as orderbyint
  from category c
  left join category p on p.id = c.parent
) c order by groupID, isparent desc, orderbyint, name

我们可以使用是否为父类来注释每个类别。然后我们可以对类别进行分组。在每个组中,订单取决于父订单。在parent.order为0时,我正在根据id执行一个订单。如果它不是0,那么orderbyint为空,然后我们将按name排序。

答案 1 :(得分:2)

当树的深度仅限于2时:

select c1.*, 
       c2.*,
       if (c2.category_parent is NULL, "parent category", "sub category") as text
from cat c1 left join cat c2 
    on c1.category_id = c2.category_parent
order by c1.category_id, c2.category_id

您可以使用条件c2.category_parent is NULL来测试类别的级别。

答案 2 :(得分:0)

我遇到了同样的问题并测试了许多示例或Tomas和JTseng解决方案。这些都缺少数字排序或子类别排序。我修改了JTseng查询,现在就可以了(对我而言),这样:

SELECT c.*,
  CASE WHEN isnull(is_par.cat_id) THEN c.cat_sort_order ELSE is_par.cat_sort_order END as sort_order,
  CASE WHEN isnull(is_par.cat_id) THEN c.cat_id ELSE is_par.cat_id END as catid ,
  CASE WHEN isnull(is_par.cat_id) THEN 0 ELSE c.cat_sort_order END as subcat_order
FROM `category` c
LEFT JOIN `category` is_par ON is_par.cat_id = c.cat_parent_id
ORDER BY  sort_order , catid, subcat_order

我在测试解决方案之后编写了这个解决方案,其中通过创建由三个字符串组成的连接字符串进行排序:第一个用于父类别的主要排序顺序,第二个用于分组父类别及其子类,第三个根据子命令对父母及其子女进行排序的字符串(并将父母猫放在第一位,给他们一个虚拟子猫排序顺序设置为0)。但是这个字符串排序给出了字母排序,而不是数字排序。因此,将JTseng转换为额外数字字段的转换顺序如下:

  • 第一个CASE WHEN用于检测某个类别是否为父类。如果它是父类,则保留父排序顺序,如果它是子类别,则其排序顺序将替换为父排序顺序
  • 第二个CASE WHEN用于替换方式,子类别id由其父类别id(这相当于JTseng groupid)
  • 第三个CASE WHEN用于将0设置为父子排序顺序并保持子猫排序顺序

要查看LEFT JOIN操作,只需在phpMyAdmin页面中执行此查询:

SELECT c.cat_id as ccatid,c.cat_sort_order as ccatsortorder, is_par.cat_id as isparcatid,is_par.cat_parent_id as ispar_catparentid,is_par.cat_sort_order as isparcatsortorder,
  CASE WHEN isnull(is_par.cat_id) THEN c.cat_sort_order ELSE is_par.cat_sort_order END as sort_order,
  CASE WHEN isnull(is_par.cat_id) THEN c.cat_id ELSE is_par.cat_id END as catid,
  CASE WHEN isnull(is_par.cat_id) THEN 0 ELSE c.cat_sort_order END as subcat_order
FROM `category` c
LEFT JOIN `category` is_par ON is_par.cat_id = c.cat_parent_id

答案 3 :(得分:0)

我找到了一种简单的方法。它按层次结构和字母顺序排列。

首先,我把SQL需要看看例子:

CREATE TABLE IF NOT EXISTS `categories` (
  `category_id` int(11) NOT NULL AUTO_INCREMENT,
  `category_parent` int(11) NOT NULL,
  `category_name` varchar(100) COLLATE latin1_spanish_ci NOT NULL,
  PRIMARY KEY (`category_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COLLATE=latin1_spanish_ci;

现在快速插入以获得结果:

INSERT INTO categoriescategory_idcategory_parentcategory_name)价值观 (1,0,'类别编号1'), (2,0,'类别编号2'), (3,0,'类别编号3'), (4,0,'类别编号4'), (5,0,'类别编号5'), (6,0,'类别编号6'), (7,2,'类别2'的第一个子类别), (8,2'类别2'的第二子类别), (9,2,'和类别2的第三个子类别(必须首先出现,因为字母顺序)'), (10,1,'类别编号1和#39;的第一个子类别), (11,1,' Ans类别编号1的第二个子类别(必须首先出现,因为按字母顺序排列)');

和SQL句子:

SELECT category_id,category_parent,category_name,
(CASE
    WHEN category_parent=category_id OR category_parent=0  THEN category_id
    WHEN category_parent<>category_id THEN category_parent
END) AS 'the_parent'
FROM categories ORDER BY the_parent ASC, category_parent ASC, category_name ASC

我希望它有用

答案 4 :(得分:0)

这是我对3个子类别level1,level2和level3

深度的回答
SELECT
    main.id AS main_id,
    level1.id AS level1_id,
    level2.id AS level2_id,
    level3.id AS level3_id
FROM
    categories AS main
LEFT OUTER JOIN categories AS level1 ON level1.parent_id = main.id
LEFT OUTER JOIN categories AS level2 ON level2.parent_id = level1.id
LEFT OUTER JOIN categories AS level3 ON level3.parent_id = level2.id
WHERE
    main.parent_id = "ID-OF-MAIN-CATEGORY"
ORDER BY
    main_id,
    level1_id,
    level2_id,
    level3_id

您的查询看起来与此类似(示意性地说)

enter image description here

希望有所帮助

答案 5 :(得分:0)

select *, if (parent_category_id is NULL, id, concat(parent_category_id, id)) as o
from category
order by o

Sample data