假设下表记录:
TABLE: foo
==========================
| foo_id | foo_parent_id |
==========================
| 1 | NULL |
| 2 | NULL |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 1 |
| 7 | 2 |
| 8 | 1 |
| 9 | NULL |
--------------------------
我希望得到前10条父记录(那些记录为foo_parent_id = NULL),紧接着是该父记录的前2个子记录。所以,我正在寻找这样的结果:
1, NULL
3, 1
5, 1
2, NULL
4, 2
7, 2
9, NULL
如何查询这样的内容?
答案 0 :(得分:3)
这是一个想法。但它基于对数据设置方式的许多假设。不断增加树下的ID,只有两个等级,等等。
SELECT f.foo_id,f.foo_parent_id FROM foo f
foo f
- 给我前面的X个parent_id (这很好,您只需调整LIMIT 10以改变要显示的父级别数)
INNER JOIN
(select foo_id from foo where foo_parent_id is null order by foo_parent_id
LIMIT 10
) top_foo_parent
on isnull(f.foo_parent_id,f.foo_id) = top_foo_parent.foo_id
WHERE
(这部分是一种hacky,因为你必须把更长的字符串用来过两个孩子)
- 这是第一个孩子,或者......
(f.foo_id in (select MIN(foo_id) from foo fc1 where fc1.foo_parent_id =f.foo_parent_id)
)
or
- 这是第二个孩子,或者......
(f.foo_id in (select MIN(foo_id) from foo fc1 where fc1.foo_parent_id =f.foo_parent_id and fc1.foo_id not in (select MIN(foo_id) from foo fc2 where fc2.foo_parent_id=f.foo_parent_id))
)
or
- 这是父母
f.foo_parent_id is null
order by isnull(f.foo_parent_id,f.foo_id)*100 + f.foo_id
所以我们在这里做的基本上是通过parent_id列进行排序,然后是略微扭曲的子列。如果parentid列为NULL,那么我们使用实际ID。这意味着出于订购目的,我们的表格如下所示:
==============================================================================
| foo_id | foo_parent_id | isnull(f.foo_parent_id,f.foo_id)
==============================================================================
| 1 | NULL | (1)
| 2 | NULL | (2)
| 3 | 1 | 1
| 4 | 2 | 2
| 5 | 1 | 1
| 7 | 2 | 2
----------------------------------------------------------------------
然后我们将该排序列乘以* 100
==============================================================================
| foo_id | foo_parent_id | isnull(f.foo_parent_id,f.foo_id)*100
==============================================================================
| 1 | NULL | 100
| 2 | NULL | 200
| 3 | 1 | 100
| 4 | 2 | 200
| 5 | 1 | 100
| 7 | 2 | 200
----------------------------------------------------------------------
最后我们将foo_id列添加到其中
==============================================================================
| foo_id | foo_parent_id | isnull(f.foo_parent_id,f.foo_id)*100 + foo_id
==============================================================================
| 1 | NULL | 101
| 2 | NULL | 202
| 3 | 1 | 103
| 4 | 2 | 204
| 5 | 1 | 105
| 7 | 2 | 207
----------------------------------------------------------------------
现在我们按该虚拟列排序表格......
==============================================================================
| foo_id | foo_parent_id | ORDER BY isnull(f.foo_parent_id,f.foo_id)*100 + foo_id
==============================================================================
| 1 | NULL | 101
| 3 | 1 | 103
| 5 | 1 | 105
| 2 | NULL | 202
| 4 | 2 | 204
| 7 | 2 | 207
----------------------------------------------------------------------
我们走了!
答案 1 :(得分:0)
我想提出另一种方法来回答这个问题:
SET @topN = 1;
SELECT foo_id, foo_parent_id
FROM (
SELECT
f.foo_id
, f.foo_parent_id
, IFNULL(f.foo_parent_id, f.foo_id) AS grp_rank
, CASE
WHEN f.foo_parent_id IS NULL
THEN @topN:= 1
ELSE
@topN:=@topN+1
END topN_rank
, f_parent.foo_id AS f_parent_foo_id
FROM
foo AS f
RIGHT JOIN (
SELECT foo_id
FROM foo
WHERE foo_parent_id IS NULL
ORDER BY foo_id LIMIT 10
) f_parent
ON f_parent.foo_id = IFNULL(f.foo_parent_id, f.foo_id)
ORDER BY grp_rank, f.foo_id
) AS foo_derived
WHERE topN_rank <= 3
一般说明:
I want to get, say, the first 10 parent records <-- SUBQUERY "f_parent"
followed by, say, the first 2 child records of that parent record. <-- topN <= 3 (PARENT + 2 CHILDREN)
工作原理:
grp_rank
NULL
foo_parent_id重置排名。这个新列topN_rank
受到排序的影响。 topN_rank
并仅返回所需的列。topN_rank
列过滤,获取每个组的前N行,每组禁止超过3行。