当前位置: 首页 > 面试题库 >

mysql过程在更新前一行中的数字引用时进行更新

路欣荣
2023-03-14
问题内容

有一张这样的桌子

 ______________________
| id | 标题| 订购|
| ---------------------- |
| 1 | test1 | 1 |
| ----- | -------- | ------- |
| 2 | test2 | 2 |
| ----- | -------- | ------- |
| 3 | test3 | 3 |
| ----- | -------- | ------- |
| 4 | test4 | 4 |
'----------------------'

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

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

然后过程或方法在更新较低的值之前重新采样顺序列中的订单列,以使其顺序更新

 ______________________
| id | 标题| 订购|
| ---------------------- |
| 1 | test1 | 2 |
| ----- | -------- | ------- |
| 2 | test2 | 3 |
| ----- | -------- | ------- |
| 3 | test3 | 1 |
| ----- | -------- | ------- |
| 4 | test4 | 4 |
'----------------------'

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


问题答案:

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

  1. 移动一行,使其在顺序中更早出现。
  2. 移动一行,以便在以后的排序中出现。

无论哪种方式都是不平凡的。目前尚不清楚“订单”列是否存在唯一约束;最终结果当然应该具有唯一的顺序。

符号:

  • “开”指的是旧值中值为“ order = n”的行
  • “ Nn”是指新值中具有“ order = n”的行

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

  • O3-> N1
  • O1-> N2
  • O2-> N3

或者,考虑移动id = 2,使它的阶数= 4:

  • O2-> N4
  • O3-> N2
  • O4-> N3

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

UPDATE AnonymousTable
   SET order = CASE
               WHEN order = $old THEN $new
               WHEN order >= $new AND order < $old THEN order + 1
               END CASE
 WHERE order BETWEEN $new AND $old;

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

UPDATE AnonymousTable
   SET order = CASE
               WHEN order = $old THEN $new
               WHEN order > $new AND order <= $old THEN order - 1
               END CASE
 WHERE order BETWEEN $old AND $new;

给定整个UPDATE的WHERE子句,您可以删除CASE中的第二个WHEN并将其替换为简单的ELSE。

UPDATE AnonymousTable
   SET order = CASE
               WHEN order = $old THEN $new
               ELSE                   order + 1
               END CASE
 WHERE order BETWEEN $new AND $old;

UPDATE AnonymousTable
   SET order = CASE
               WHEN order = $old THEN $new
               ELSE                   order - 1
               END CASE
 WHERE order BETWEEN $old AND $new;

我认为存储过程是有序的-根据输入参数$ old,$ new在两个语句之间进行选择。您可能能够明智地混合使用诸如($old - $new) / ABS($old - $new)‘和’MIN($old, $new)以及’和’这样的表达式,MAX($old, $new)其中MIN /
MAX不是集合,而是一对值的比较器函数(在Fortran中以及其他编程语言中) 。

请注意,我假设在执行单个SQL语句时,唯一性约束(如果有)在每行更改时均不强制执行-
仅在语句完成时执行。这是必需的,因为您实际上无法控制行的处理顺序。我知道DBMS会在哪里引起麻烦;我知道别人不会。

所有这些都可以在一个SQL语句中完成-但您确实希望存储过程对该语句的参数进行分类。我使用IBM Informix Dynamic Server(在MacOSX 10.6.2上为11.50.FC6),它是在语句末尾对“order”列实施唯一约束的DBMS之一。我在没有UNIQUE约束的情况下进行了SQL的开发;当然也可以。(是的,IDS允许您回滚CREATE
TABLE和CREATE PROCEDURE之类的DDL语句。您说什么?您的DBMS没有?太古怪了!)

BEGIN WORK;
CREATE TABLE AnonymousTable
(
    id      INTEGER NOT NULL PRIMARY KEY,
    title   VARCHAR(10) NOT NULL,
    order   INTEGER NOT NULL UNIQUE
);
INSERT INTO AnonymousTable VALUES(1, 'test1', 1);
INSERT INTO AnonymousTable VALUES(2, 'test2', 2);
INSERT INTO AnonymousTable VALUES(3, 'test3', 3);
INSERT INTO AnonymousTable VALUES(4, 'test4', 4);

SELECT * FROM AnonymousTable ORDER BY order;

CREATE PROCEDURE move_old_to_new(old INTEGER, new INTEGER)
    DEFINE v_min, v_max, v_gap, v_inc INTEGER;
    IF old = new OR old IS NULL OR new IS NULL THEN
        RETURN;
    END IF;
    LET v_min = old;
    IF new < old THEN
        LET v_min = new;
    END IF;
    LET v_max = old;
    IF new > old THEN
        LET v_max = new;
    END IF;
    LET v_gap = v_max - v_min + 1;
    LET v_inc = (old - new) / (v_max - v_min);
    UPDATE AnonymousTable
       SET order = v_min + MOD(order - v_min + v_inc + v_gap, v_gap)
     WHERE order BETWEEN v_min AND v_max;
END PROCEDURE;

EXECUTE PROCEDURE move_old_to_new(3,1);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(1,3);
SELECT * FROM AnonymousTable ORDER BY order;

INSERT INTO AnonymousTable VALUES(5, 'test5', 5);
INSERT INTO AnonymousTable VALUES(6, 'test6', 6);
INSERT INTO AnonymousTable VALUES(7, 'test7', 7);
INSERT INTO AnonymousTable VALUES(8, 'test8', 8);

EXECUTE PROCEDURE move_old_to_new(3,6);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(6,3);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(7,2);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(2,7);
SELECT * FROM AnonymousTable ORDER BY order;

ROLLBACK WORK;

带有相反编号的存储过程调用对每次都恢复为原始顺序。显然,我可以重新定义v_inc变量,以便它不是只是+/- 1,而是’ LET v_inc =v_inc - v_min + v_gap;‘,然后MOD表达式将只是’ MOD(order + v_inc,v_gap)‘。我没有检查这是否适用于负数。

读者可以自己练习如何适应MySQL或其他DBMS。



 类似资料:
  • 问题内容: 我有一个页面,其中发生了许多耗时的功能。我想做的是在过程的每个步骤完成后,更新网页以使用户知道刚刚完成的步骤。本质上,用户提交查询,然后服务器查询数据库,处理数据,绘制图像并在页面上显示结果。我想让网页说出该功能执行的步骤。它会说“先查询”然后“正在处理” …等等。 伪: 我已经研究过使用Ajax来更新页面而不重新加载它,但是根据我的简单理解(对Ajax零经验),客户端将向服务器请求文

  • 问题内容: 有没有简单的方法来选择更新的行? 我试图每次读取行时都存储时间戳,以便能够删除长时间未读取的数据。 首先,我首先尝试执行查询,甚至发现有点慢但是简单的解决方案,例如 但我仍然想找到一种正常的方法来做到这一点。 我还认为先更新时间然后选择更新的行应该容易得多,但是即使如此,我也没有找到任何东西 问题答案: 声明该列,如下所示: 然后,每当更新一行时,该列就会自动更新。 更新: 我认为没有

  • 问题内容: MySQL的新版本8.0现在支持 Common Table Expressions 。 根据手册: SELECT,UPDATE和DELETE语句的开头允许使用WITH子句: 因此,我认为,鉴于下表: 我可以使用以下查询: 为了从表中删除重复项,就像在 SQL Server中一样 。 原来我错了。当我尝试从MySQL Workbench 执行stament时出现错误: 错误代码:1146

  • 在游标和循环的帮助下,我将记录插入表中。关闭游标后,我编写了update语句来更新游标插入的一些记录,这样reords就不会更新。但我在外面进行了查询,然后更新了记录 我的尝试是删除程序,如果存在kpsf_inopdormantac; 请帮帮我

  • 问题内容: 我有以下UPDATE语句: 在此示例中,该函数每行被调用三次,这是错误的-我希望该函数的每行仅被调用一次。 我正在使用PostgreSQL 8.4数据库。如何编写正确的更新? 我已经尝试过这样的事情: 但这没有用,因为整个更新语句仅被调用了 一次 。 问题答案: 您是否尝试过Postgres的非标准条款?我想这会起作用 请注意,我强制在子选择内每个记录仅被调用一次。然后,我将自我加入并

  • 问题内容: 我如何查找我的更新是否成功?我使用where uniqueName = name进行更新,因此我应该始终只更新0行或1。什么是检查我是否更新了行的好方法? 问题答案: 将返回受更新影响的行数。 http://us.php.net/manual/zh/function.mysql-affected- rows.php