11

这是表结构

id   parent_id   name
1    0           BMW
2    0           Mercedez
3    0           Porsche
4    1           3 Series
5    2           E60
6    1           5 Series
7    3           Cayenne

我怎样才能将表格显示为

BMW
3 Series
5 Series
Mercedez
E60
Porsche
Cayenne 

上表显示升序 id 后跟与该 id 关联的 parent_id,然后转到第二个 id,依此类推。我需要一个查询,是否可以这样做?

4

1 回答 1

23

尝试这个:

SELECT
  name,
  CASE WHEN parent_id = 0 THEN id ELSE parent_id END AS Sort
FROM
  cars
ORDER BY
  Sort,
  id

http://sqlfiddle.com/#!2/9b05f/3


编辑:

鉴于这个答案不断得到支持,我重新审视了这个问题并发现了一个缺陷。如果由于某种原因,父母的 ID 比孩子的 ID 高,那么排序就会混乱。仅当父 ID 小于所有子 ID 时,上述查询才有效。

为了演示这个问题,假设表格如下所示:

id   parent_id   name
8    0           BMW
2    0           Mercedez
3    0           Porsche
4    8           3 Series
5    2           E60
6    8           5 Series
7    3           Cayenne

注意现在有BMW一个8而不是1。结果将如下所示:id

Mercedez
E60
Porsche
Cayenne
3 Series
5 Series
BMW

请注意,BMW出现在列表的底部,它的孩子之后!这是因为二次排序按 排序id,如果父 ID 恰好高于任何子 ID,则父 ID 可能不会显示在子 ID 之上。

此查询将解决该问题:

SELECT
  name
FROM
  cars
ORDER BY
  CASE WHEN parent_id = 0 THEN id ELSE parent_id END, -- another way of writing it: IFNULL(NULLIF(parent_id, 0), id)
  parent_id,
  id

http://sqlfiddle.com/#!2/6d6d73/3

为了解释这里发生了什么,您首先按父行的id字段和子行的字段进行排序parent_id。如果您按此排序,则所有子级将与其父级分组,并且整个列表将按父级id字段排序。

但这并没有设置家庭内的排序,因此父母可以出现在家庭中的任何地方(父母可以出现在顶部,或者它可能在中间,或者它可能是最后一个)。

这就是其他两个排序字段的来源。第二个字段按 排序parent_id,父行的parent_id字段始终为0。安全地假设您的 ID 字段始终为正,这意味着父记录将始终显示在家庭中的顶部。其余的孩子都将具有相同的值parent_id,因此第三个排序字段按其id字段对家庭中的孩子进行排序。这也可以更改为name,具体取决于您希望孩子如何排序。

于 2013-06-17T12:36:44.447 回答