如何正确排序 SQL 中的物化路径?

How do I properly sort a materialized paths in SQL?

我正在使用物化路径在 SQl 中存储树结构(在我的例子中是 MySQL 5.7)。我将路径存储为斜杠分隔的 slug。我读过的所有教程都说按路径对行进行排序以按正确的顺序提取它,但是当部分路径具有相似的前缀时它似乎不起作用。

一些示例代码:

CREATE TABLE categories (
  id int(11),
  parent_id int(11) DEFAULT NULL,
  slug varchar(255),
  path varchar(255)
);

INSERT INTO categories VALUES
  (1, null, 'foo', '/foo'),
  (2, 1, 'bar', '/foo/bar'),
  (3, null, 'foo-it', '/foo-it'),
  (4, 3, 'boy', '/foo-it/boy');

现在,按路径排序时我得到了错误的顺序:

SELECT * FROM categories ORDER BY path;

输出:

+------+-----------+--------+-------------+
| id   | parent_id | slug   | path        |
+------+-----------+--------+-------------+
|    1 |      NULL | foo    | /foo        |
|    3 |      NULL | foo-it | /foo-it     |
|    4 |         3 | boy    | /foo-it/boy |
|    2 |         1 | bar    | /foo/bar    |
+------+-----------+--------+-------------+
4 rows in set (0.00 sec)

这似乎是因为 - 在大多数(所有?)排序规则中先于 /。

疯狂的是,unix sort 命令行实用程序做了正确的事情。如果我将所有路径放在一个文件中并对其进行排序,我会得到正确的输出:

$ sort paths.txt 
/foo
/foo/bar
/foo-it
/foo-it/boy

有什么方法可以使 MySQL 树正确排序吗?以与 unix 的排序实用程序相同的方式对其进行排序?也许是不同的归类之类的?或者还有其他技巧吗?

试试这个:

SELECT * FROM categories ORDER BY path + '/';

产生:

/foo-it
/foo-it/boy
/foo
/foo/bar

/foo 排在 /foo-it 之后,因为 /foo//foo- 之后。

您可以 fiddle 有点像将 - 替换为排序中 / 之后的内容,但不允许出现在路径或文件名中。

SELECT * FROM categories ORDER BY replace(path,'-','?') + '/';

产生:

/foo
/foo/bar
/foo-it
/foo-it/boy