简体   繁体   中英

Order by in a self-referencing table

Let's say I have the following table with data:

+----+-----------+-----------+---------+
| id | name      | parent_id | prev_id |
+----+-----------+-----------+---------+
| 1  | Section 1 | NULL      | NULL    |
| 2  | Item 1.1  | 1         | NULL    |
| 3  | Item 1.2  | 1         | 2       |
| 4  | Item 1.3  | 1         | 3       |
| 5  | Section 2 | NULL      | 1       |
| 6  | Item 2.1  | 5         | NULL    |
| 7  | Item 2.2  | 5         | 6       |
| 8  | Item 2.3  | 5         | 7       |
| 9  | Item 1.4  | 1         | 4       |
+----+-----------+-----------+---------+

Here's how it works:

  • parent_id and prev_id are both foreign keys to id
  • parent_id is used to differentiate between a section and sub-section (item)
  • ie if parent_id is NULL, then it is a section; otherwise it is an item
  • prev_id is used to indicate the last section or last item in the section
  • ie if the row is a section, then prev_id will point to the row of the previous section; if the row is an item, then prev_id will point to the row of the last item in the section
  • if prev_id is NULL, then it is the first section or first item in the section
  • if parent_id and prev_id are both NULL, then it is the first section

So, is there a way to order it using SQL so that it looks like this:

+----+-----------+-----------+---------+
| id | name      | parent_id | prev_id |
+----+-----------+-----------+---------+
| 1  | Section 1 | NULL      | NULL    |
| 2  | Item 1.1  | 1         | NULL    |
| 3  | Item 1.2  | 1         | 2       |
| 4  | Item 1.3  | 1         | 3       |
| 9  | Item 1.4  | 1         | 4       | <---
| 5  | Section 2 | NULL      | 1       |
| 6  | Item 2.1  | 5         | NULL    |
| 7  | Item 2.2  | 5         | 6       |
| 8  | Item 2.3  | 5         | 7       |
+----+-----------+-----------+---------+

I would like so that

  • The first section, followed by its items, appears at the top
  • For each subsequent section, show the section followed by the items of that section

Edit: Here's a query that I came up with:

SELECT id, name, parent_id, prev_id FROM
((
    SELECT id, name, parent_id, prev_id, id AS some_id
    FROM learning_paths
    WHERE parent_id IS NULL
)
UNION ALL
(
    SELECT id, name, parent_id, prev_id, parent_id AS some_id
    FROM learning_paths
    WHERE parent_id IS NOT NULL
)) t
ORDER BY t.some_id, prev_id

This version works:

order by coalesce(parentid, id),
         (parentid is null) desc,
         coalesce(previd, parentid, id),
         previd,
         id

There might be simpler versions around.

Here is a SQL Fiddle (admittedly in Postgres, but that shouldn't make a difference for this problem).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM