Mysql 在类别树中的某个位置选择具有类别id的记录
我正在显示一个类别树,在每个分支旁边,我想要一个相同级别或更低级别的列表数 所有列表都具有最低类别级别的catid。i、 e.如果有较低的类别级别可用,则无法将特定catid应用于列表 例如,在下面的listings表中,您无法找到catid=24的列表,因为这还不是该分支树中的最低级别 在我的类别数据库中,最多有4个级别0-3 以下是表格: 所有类别表 列表表 因此,我的HTML类别树应该如下所示: HTML 因此,在我的html和jQuery代码中,我将任何级别的特定catid传递给查询,它应该会找到处于或低于该级别的列表 我已经试了几个小时了,到目前为止我的努力都不值得展示。但无论如何我会 编辑:到目前为止,我的努力没有笑,在尝试了几个小时不同的事情后,它变得混乱了:Mysql 在类别树中的某个位置选择具有类别id的记录,mysql,sql,Mysql,Sql,我正在显示一个类别树,在每个分支旁边,我想要一个相同级别或更低级别的列表数 所有列表都具有最低类别级别的catid。i、 e.如果有较低的类别级别可用,则无法将特定catid应用于列表 例如,在下面的listings表中,您无法找到catid=24的列表,因为这还不是该分支树中的最低级别 在我的类别数据库中,最多有4个级别0-3 以下是表格: 所有类别表 列表表 因此,我的HTML类别树应该如下所示: HTML 因此,在我的html和jQuery代码中,我将任何级别的特定catid传递给查询,它
select l.record_id
from listings l
where catid in (
select record_id
from all_categories
where record_id = 5915)
or catid in (
select parent_category_id
from all_categories
where parent_category_id = 5915)
or catid in (
select parent_id
from all_categories
where parent_id = 5915)
子级的0级父级\u id保留在“所有\u类别”表中 因此,一个孩子可以通过他们共同的父母id链接到其他孩子。 然后同时包含级别0 困难在于给定的子id不在列表表中。 因此,要检索列表记录的id,它必须通过类别 可以找到rextester上的测试 选择 类别记录id为catId, pl.listId作为ListingCount, 猫级 从…起 选择 cat1.1父项id, MAXlist.record_id作为listId 从所有类别中选择cat1 将所有类别连接为cat2上的cat2.parent\u id=cat1.parent\u id 在list.cat\u id=cat2.record\u id上加入列表列表 其中cat1.record_id=5915 按cat1.parent\u id分组 作为pl 以cat.parent\u id=pl.parent\u id或cat.record\u id=pl.parent\u id的形式左键连接所有类别 按类别记录的订单,类别级别; 结果:
catId ListingCount level
24 1 0
5915 1 1
7569 1 2
该级别也包含在查询中,因为它可以用于生成HTML中的类别树
请注意,如果listings表仅包含级别0的cat_id,则查询可以简化很多。假设树的最大深度为四级,则可以使用多个左连接来检索完整树或子树。但这并不是超高效的。考虑下面的查询:
SET @subtree_id = 1;
SELECT
c0.category_id AS c0_id, c0.name AS c0_name,
c1.category_id AS c1_id, c1.name AS c1_name,
c2.category_id AS c2_id, c2.name AS c2_name,
c3.category_id AS c3_id, c3.name AS c3_name,
l.listing_id
FROM category AS c0
LEFT JOIN category AS c1 ON c1.parent_id = c0.category_id
LEFT JOIN category AS c2 ON c2.parent_id = c1.category_id
LEFT JOIN category AS c3 ON c3.parent_id = c2.category_id
LEFT JOIN listing AS l ON l.category_id = c0.category_id
OR l.category_id = c1.category_id
OR l.category_id = c2.category_id
OR l.category_id = c3.category_id
WHERE c0.category_id = @subtree_id;
它将产生如下结果:
| c0_id | c0_name | c1_id | c1_name | c2_id | c2_name | c3_id | c3_name | listing_id |
|-------|-------------|-------|-------------|-------|-----------|-------|------------|------------|
| 1 | Real Estate | 2 | Residential | 3 | House | NULL | NULL | NULL |
| 1 | Real Estate | 2 | Residential | 4 | Apartment | NULL | NULL | 1 |
| 1 | Real Estate | 2 | Residential | 4 | Apartment | NULL | NULL | 2 |
| 1 | Real Estate | 2 | Residential | 4 | Apartment | NULL | NULL | 3 |
| 1 | Real Estate | 2 | Residential | 5 | Condo | NULL | NULL | NULL |
| 1 | Real Estate | 6 | Commercial | 7 | Office | NULL | NULL | 4 |
| 1 | Real Estate | 6 | Commercial | 8 | Retail | NULL | NULL | 5 |
| 1 | Real Estate | 6 | Commercial | 9 | Other | 10 | Industrial | 6 |
不幸的是,它只包含完整路径。要匹配预期结果,只需将每行分成4行:
SET @subtree_id = 1;
SELECT
CASE WHEN level >= 0 THEN c0_id END AS c0_id, CASE WHEN level >= 0 THEN c0_name END AS c0_name,
CASE WHEN level >= 1 THEN c1_id END AS c1_id, CASE WHEN level >= 1 THEN c1_name END AS c1_name,
CASE WHEN level >= 2 THEN c2_id END AS c2_id, CASE WHEN level >= 2 THEN c2_name END AS c2_name,
CASE WHEN level >= 3 THEN c3_id END AS c3_id, CASE WHEN level >= 3 THEN c3_name END AS c3_name,
COUNT(listing_id) AS lc
FROM (
SELECT
c0.category_id AS c0_id, c0.name AS c0_name,
c1.category_id AS c1_id, c1.name AS c1_name,
c2.category_id AS c2_id, c2.name AS c2_name,
c3.category_id AS c3_id, c3.name AS c3_name,
l.listing_id
FROM category AS c0
LEFT JOIN category AS c1 ON c1.parent_id = c0.category_id
LEFT JOIN category AS c2 ON c2.parent_id = c1.category_id
LEFT JOIN category AS c3 ON c3.parent_id = c2.category_id
LEFT JOIN listing AS l ON l.category_id = c0.category_id
OR l.category_id = c1.category_id
OR l.category_id = c2.category_id
OR l.category_id = c3.category_id
WHERE c0.category_id = @subtree_id
) AS paths
INNER JOIN (
SELECT 0 AS level UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3
) AS levels ON level = 0 AND c0_id IS NOT NULL
OR level = 1 AND c1_id IS NOT NULL
OR level = 2 AND c2_id IS NOT NULL
OR level = 3 AND c3_id IS NOT NULL
GROUP BY 1, 2, 3, 4, 5, 6, 7, 8
ORDER BY 2, 1, 4, 3, 6, 5, 8, 7
在mysql 8中,有一个with函数递归运行,您可以获得catId的级别 结构->id类别父项\u id ->1,24,空,25915,1,37569,2,4,3,1
唯一的限制是,在我的sql 8.x版本中,代码可以正常运行。您可以询问的任何问题都可以使用此方法。此方法称为cet hope it help对于每个记录id,左键连接子项,然后计算每个级别的唯一值并将它们相加
select n.record_id
count(distinct n.record_id)+count(distinct n2.record_id)+count(distinct
n3.record_id)+count(distinct n4.record_id) listingcount
from all_categories n
left join all_categories n2 on n.record_id=n2.parent_category_id
left join all_categories n3 on n2.record_id=n3.parent_category_id
left join all_categories n4 on n3.record_id=n4.parent_category_id
group by n.record_id
你有一个神秘的数据结构,但问题似乎并不那么难。这似乎是你想要的:
select c2.record_id, count(*)
from listings l join
all_categories c
on l.cat_id = c.record_id join
all_categories c2
on c2.record_id in (c.record_id, c.parent_category_id, c.parent_id)
group by c2.record_id, l.cat_id
order by l.cat_id, c2.record_id;
这个想法很简单。表all_categories具有完整的层次结构。基本上,您需要将层次结构的所有级别移动到单独的行中,以便对它们进行聚合
这就是连接到c2的功能。其余的只是聚合。我认为这适合于递归sql
CREATE FUNCTION f_total_listings(@root_id INT) RETURNS INT AS
BEGIN
DECLARE @listing_count INT;
WITH cat (record_id, parent_category_id) AS
(
SELECT root.record_id, root.parent_category_id
FROM all_categories AS root
WHERE root.parent_category_id = @root_id
UNION ALL
SELECT child.record_id, child.parent_category_id
FROM cat AS parent, all_categories AS child
WHERE parent.record_id = child.parent_category_id
)
SELECT @listing_count = count(*)
FROM listings l
JOIN cat ON l.cat_id = cat.record_id;
RETURN @listing_count;
END;
SELECT record_id, f_total_listings(record_id) FROM all_categories
SQL问题通常需要仔细选择覆盖所有边缘情况的最小但完整的样本数据,以及相应的表格形式的预期输出。读一次:你有什么版本?使用MySQL 8.0的递归CTE,此任务可能会更容易。是否要显示没有列表的空类别?
WITH recursive parent(id,parent_id,Levels) AS
(
select id,parent_id, 0 as Levels from table where id =1 //condition
union all
select c.id,c.parent_id,(Levels+1) as Levels from table as c inner join parent as p1 on p1.id = c.parent_id
)
SELECT *
FROM parent
select n.record_id
count(distinct n.record_id)+count(distinct n2.record_id)+count(distinct
n3.record_id)+count(distinct n4.record_id) listingcount
from all_categories n
left join all_categories n2 on n.record_id=n2.parent_category_id
left join all_categories n3 on n2.record_id=n3.parent_category_id
left join all_categories n4 on n3.record_id=n4.parent_category_id
group by n.record_id
select c2.record_id, count(*)
from listings l join
all_categories c
on l.cat_id = c.record_id join
all_categories c2
on c2.record_id in (c.record_id, c.parent_category_id, c.parent_id)
group by c2.record_id, l.cat_id
order by l.cat_id, c2.record_id;
CREATE FUNCTION f_total_listings(@root_id INT) RETURNS INT AS
BEGIN
DECLARE @listing_count INT;
WITH cat (record_id, parent_category_id) AS
(
SELECT root.record_id, root.parent_category_id
FROM all_categories AS root
WHERE root.parent_category_id = @root_id
UNION ALL
SELECT child.record_id, child.parent_category_id
FROM cat AS parent, all_categories AS child
WHERE parent.record_id = child.parent_category_id
)
SELECT @listing_count = count(*)
FROM listings l
JOIN cat ON l.cat_id = cat.record_id;
RETURN @listing_count;
END;
SELECT record_id, f_total_listings(record_id) FROM all_categories