【问题标题】:order by next and previous按下一个和上一个排序
【发布时间】:2019-02-12 15:54:16
【问题描述】:

我在 MySQL 中有 SQL 表,其中包含以下信息:

id | prev | next
1  | 7    |  2
2  | 1    |  3
3  | 2    |  6
4  | 6    |  5
5  | 4    |  null
6  | 3    |  4
7  | null |  1

我想使用 SQL 查询来按下一列升序或按上一列降序排序,其中 next 是指向下一行的指针,previous 是指向上一行的指针,所以如果我想按升序排序,例如我会得到如下结果:

id | prev | next
7  | null |  1
1  | 7    |  2
2  | 1    |  3
3  | 2    |  6
6  | 3    |  4
4  | 6    |  5
5  | 4    |  null

那该怎么做呢?

更新:第一个表是按 id 排序的,但我想以我得到第二个表的方式排序,第二个表是通过下一个值产生的,所以第一行是 7 (id=7)因为 prev 为 null 而 second 为 1,因为第一行的下一列是 1,然后第三行是 2,因为 2 是第二行下一列的值,依此类推。

【问题讨论】:

  • 到目前为止你尝试了什么?
  • ORDER BY next ASCORDER BY prev DESC
  • 为什么在next 列 6 中排在 4 和 5 之前?
  • 您使用的是哪个版本的 MySQL?
  • @JuanCarlosOropeza 第一个表是按 id 排序的,但我想以我得到第二个表的方式排序,第二个表是通过下一个值产生的,所以第一行是 7 (id=7) 因为 prev 为 null 而 second 为 1,因为第一行的下一列是 1,然后第三行是 2,因为 2 是第二行下一列的值,依此类推。

标签: mysql sql sql-order-by


【解决方案1】:

您好,我找到了一个带有程序的解决方案。 当我有这样的表时:

CREATE TABLE `zz_test` (
  `id` int(11) NOT NULL,
  `prev` int(11) DEFAULT NULL,
  `next` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;

和记录:

INSERT INTO `zz_test` VALUES ('1', '7', '2');
INSERT INTO `zz_test` VALUES ('2', '1', '3');
INSERT INTO `zz_test` VALUES ('3', '2', '6');
INSERT INTO `zz_test` VALUES ('4', '6', '5');
INSERT INTO `zz_test` VALUES ('5', '4', null);
INSERT INTO `zz_test` VALUES ('6', '3', '4');
INSERT INTO `zz_test` VALUES ('7', null, '1');

可以按这个程序排序:

DROP PROCEDURE IF EXISTS zz_sort_test;
CREATE PROCEDURE zz_sort_test()
BEGIN

    DECLARE next_value INT DEFAULT 1;
    DECLARE rows_count INT DEFAULT 0;
    DECLARE iterations INT DEFAULT 0;

    DECLARE cid, cnext, cprev INT DEFAULT NULL;

    DROP TEMPORARY TABLE IF EXISTS sorted;
    CREATE TEMPORARY TABLE IF NOT EXISTS sorted (iter INT, id INT, prev INT, next INT);

    SELECT COUNT(1) INTO rows_count FROM zz_test;

    #first row
    SELECT next INTO next_value FROM zz_test WHERE prev IS NULL LIMIT 1;
    SELECT id, prev, next INTO cid, cprev, cnext FROM zz_test WHERE next_value = next;
    INSERT INTO sorted (iter, id, prev, next) VALUES (-1, cid, cprev, cnext);

    loopy: LOOP
        SET iterations = iterations + 1;
        IF rows_count = iterations THEN
            LEAVE loopy;
        END IF;

        SELECT id, prev, next INTO cid, cprev, cnext FROM zz_test WHERE next_value = id;
        SET next_value := cnext;

        INSERT INTO sorted (iter, id, prev, next) VALUES (iterations, cid, cprev, cnext);
    END LOOP loopy;

    SELECT id, prev, next FROM sorted ORDER BY iter;

END

解释那里发生的事情:

  • 它创建临时表来存储选定的数据(排序
  • 从 zz_test 表中选择行数 (rows_count)
  • 选择最小(不带空)下一个值(next_value)并将行插入到临时表中
  • 在循环中保存 next_value 以供下一次迭代搜索
  • 以及知道何时停止的迭代次数(迭代次数
  • 临时表中的行使用迭代计数器插入,因为最后它有助于排序
  • 最后,简单返回所有从临时表排序的结果

您可以通过以下方式调用它:

call zz_sort_test;

我用mysql测试过5.7.18

编辑: 我编辑了答案,所以第一个选择的行将是 prev value = NULL 我为 prev = NULL 的行超过一行的情况添加了 LIMIT 1

【讨论】:

  • 我在你的数据上尝试了你的解决方案,我得到了正确的结果,但是有一个小问题,如果你改变了这一行,第一行通常不需要在下一列中有 1 个值: SELECT MIN(next) INTO next_value FROM zz_test WHERE next IS NOT NULL; 变成 SELECT next INTO next_value FROM zz_test WHERE prev IS NULL; 所以解决方案将变得通用,因为通常第一行在上一列中必须为空,因为它前面没有记录,无论如何感谢您的解决方案,我会投票给它
  • 嗨,我根据您的要求编辑了答案(从 prev 为空的行开始)
猜你喜欢
  • 1970-01-01
  • 2014-10-28
  • 2011-12-22
  • 1970-01-01
  • 2021-11-25
  • 2013-12-14
  • 2017-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多