mysql过程更新一个更新前一行中的数字引用

mar*_*ial 6 mysql sql stored-procedures

有一张像这样的桌子

 ______________________
| id  |  title | order |
|----------------------|
|  1  |  test1 |   1   |
|-----|--------|-------|
|  2  |  test2 |   2   |
|-----|--------|-------|
|  3  |  test3 |   3   |
|-----|--------|-------|
|  4  |  test4 |   4   |
'----------------------'

当我在我的mysql shell中引入一行的单个更新

 $sql> UPDATE `table` SET order=1 WHERE id=3; 

然后,程序或方法重新采样更新前值中的订单列,以便像这样更新其订单

 ______________________
| id  |  title | order |
|----------------------|
|  1  |  test1 |   2   |
|-----|--------|-------|
|  2  |  test2 |   3   |
|-----|--------|-------|
|  3  |  test3 |   1   |
|-----|--------|-------|
|  4  |  test4 |   4   |
'----------------------'

任何帮助将不胜感激,谢谢!

Jon*_*ler 4

我认为有两种情况需要考虑:

\n\n
    \n
  1. 移动一行,使其在排序中出现在前面。
  2. \n
  3. 移动一行,使其出现在排序中靠后的位置。
  4. \n
\n\n

不管怎样,这都是不平凡的。不清楚“order”列是否有唯一约束;最终结果当然应该有一个独特的顺序。

\n\n

符号:

\n\n
    \n
  • “On”是指旧值中值为“order = n”的行
  • \n
  • “Nn”指的是新值中“order = n”的行
  • \n
\n\n

在示例中(案例 1 的说明):

\n\n
    \n
  • O3 --> N1
  • \n
  • O1 --> N2
  • \n
  • 氧气 --> 氮气
  • \n
\n\n

作为替代方案,请考虑移动 id = 2,使其 order = 4:

\n\n
    \n
  • 氧气 --> 氮气
  • \n
  • O3 --> N2
  • \n
  • O4 --> N3
  • \n
\n\n

您基本上是从“其他”行中添加或减去一行,这些行是在移动行的旧位置和移动行的新位置之间按旧顺序排列的行。在伪代码中,使用 $old 和 $new 来标识移动行的前后位置,并处理情况 1 ($old > $new):

\n\n
UPDATE AnonymousTable\n   SET order = CASE\n               WHEN order = $old THEN $new\n               WHEN order >= $new AND order < $old THEN order + 1\n               END CASE\n WHERE order BETWEEN $new AND $old;\n
Run Code Online (Sandbox Code Playgroud)\n\n

情况 2 ($old < $new) 对应的代码是:

\n\n
UPDATE AnonymousTable\n   SET order = CASE\n               WHEN order = $old THEN $new\n               WHEN order > $new AND order <= $old THEN order - 1\n               END CASE\n WHERE order BETWEEN $old AND $new;\n
Run Code Online (Sandbox Code Playgroud)\n\n

鉴于 UPDATE 上的 WHERE 子句作为一个整体,您也许可以删除 CASE 中的第二个 WHEN 并将其替换为简单的 ELSE。

\n\n
UPDATE AnonymousTable\n   SET order = CASE\n               WHEN order = $old THEN $new\n               ELSE                   order + 1\n               END CASE\n WHERE order BETWEEN $new AND $old;\n\nUPDATE AnonymousTable\n   SET order = CASE\n               WHEN order = $old THEN $new\n               ELSE                   order - 1\n               END CASE\n WHERE order BETWEEN $old AND $new;\n
Run Code Online (Sandbox Code Playgroud)\n\n

我认为存储过程是有序的 - 根据输入参数 $old、$new 在两个语句之间进行选择。您也许可以使用表达式的明智组合来执行某些操作,例如“ ($old - $new) / ABS($old - $new)”和“ MIN($old, $new)”和“ MAX($old, $new)”,其中 MIN/MAX 不是聚合,而是一对值的比较器函数(如 Fortran 和其他编程语言中所示) 。

\n\n

请注意,我假设在执行单个 SQL 语句时,只有当语句完成时,才会在每行更改时强制执行唯一性约束(如果有)。这是必要的,因为您实际上无法控制处理行的顺序。我知道 DBMS 会造成麻烦;我知道其他人不会这样做。

\n\n
\n\n

这一切都可以在单个 SQL 语句中完成 - 但您确实需要一个存储过程来对语句的参数进行排序。我使用 IBM Informix Dynamic Server(MacOS X 10.6.2 上的 11.50.FC6),它是对语句末尾的“order”列强制执行唯一约束的 DBMS 之一。我在没有UNIQUE约束的情况下开发了SQL;当然,这也有效。(是的,IDS 确实允许您回滚 DDL 语句,例如 CREATE TABLE 和 CREATE PROCEDURE。您说什么?您的 DBMS 不允许?多么奇怪!)

\n\n
BEGIN WORK;\nCREATE TABLE AnonymousTable\n(\n    id      INTEGER NOT NULL PRIMARY KEY,\n    title   VARCHAR(10) NOT NULL,\n    order   INTEGER NOT NULL UNIQUE\n);\nINSERT INTO AnonymousTable VALUES(1, 'test1', 1);\nINSERT INTO AnonymousTable VALUES(2, 'test2', 2);\nINSERT INTO AnonymousTable VALUES(3, 'test3', 3);\nINSERT INTO AnonymousTable VALUES(4, 'test4', 4);\n\nSELECT * FROM AnonymousTable ORDER BY order;\n\nCREATE PROCEDURE move_old_to_new(old INTEGER, new INTEGER)\n    DEFINE v_min, v_max, v_gap, v_inc INTEGER;\n    IF old = new OR old IS NULL OR new IS NULL THEN\n        RETURN;\n    END IF;\n    LET v_min = old;\n    IF new < old THEN\n        LET v_min = new;\n    END IF;\n    LET v_max = old;\n    IF new > old THEN\n        LET v_max = new;\n    END IF;\n    LET v_gap = v_max - v_min + 1;\n    LET v_inc = (old - new) / (v_max - v_min);\n    UPDATE AnonymousTable\n       SET order = v_min + MOD(order - v_min + v_inc + v_gap, v_gap)\n     WHERE order BETWEEN v_min AND v_max;\nEND PROCEDURE;\n\nEXECUTE PROCEDURE move_old_to_new(3,1);\nSELECT * FROM AnonymousTable ORDER BY order;\nEXECUTE PROCEDURE move_old_to_new(1,3);\nSELECT * FROM AnonymousTable ORDER BY order;\n\nINSERT INTO AnonymousTable VALUES(5, 'test5', 5);\nINSERT INTO AnonymousTable VALUES(6, 'test6', 6);\nINSERT INTO AnonymousTable VALUES(7, 'test7', 7);\nINSERT INTO AnonymousTable VALUES(8, 'test8', 8);\n\nEXECUTE PROCEDURE move_old_to_new(3,6);\nSELECT * FROM AnonymousTable ORDER BY order;\nEXECUTE PROCEDURE move_old_to_new(6,3);\nSELECT * FROM AnonymousTable ORDER BY order;\nEXECUTE PROCEDURE move_old_to_new(7,2);\nSELECT * FROM AnonymousTable ORDER BY order;\nEXECUTE PROCEDURE move_old_to_new(2,7);\nSELECT * FROM AnonymousTable ORDER BY order;\n\nROLLBACK WORK;\n
Run Code Online (Sandbox Code Playgroud)\n\n

数字相反的存储过程调用对每次都会恢复原始顺序。显然,我可以重新定义该v_inc变量,使其不再只是 \xc2\xb11,而是“ LET v_inc = v_inc - v_min + v_gap;”,然后 MOD 表达式将只是“ MOD(order + v_inc, v_gap)”。我还没有检查这是否适用于负数。

\n\n

适应 MySQL 或其他 DBMS 留给读者作为练习。

\n