SQL数据库引擎如何交换两列值?

XMe*_*i01 6 database-engine update

我想交换表中两列的值,我发现在 SQL 中我们可以通过使用 Update 来做到这一点:

update the_table set first_name = last_name, last_name = first_name;
Run Code Online (Sandbox Code Playgroud)

它有效但我想知道 SQL 如何能够做到这一点而不覆盖其他列中的列中的数据?

Cha*_*ace 10

@mustaccio 已经回答了这是如何物理实现的。


逻辑规范如下

=语句UPDATE SET中右侧的列必须来自应用更新之前的值。因此交换值很简单,因为右侧始终引用旧值。

了解原因的另一种方法是考虑对语句进行等效重写:

update the_table 
set (first_name, last_name) = (last_name, first_name);
Run Code Online (Sandbox Code Playgroud)

并非所有 SQL 产品都实现了这一点,但根据 SQL 标准,它是等效的,并且在实现它的地方,它的工作方式与您的完全一样。


至于是否保证:是的。它是由 SQL 规范强制执行的,据我所知,大多数 DBMS 都实现了这一要求(MySQL 和派生/分叉产品,例如 MariaDB 是一个例外,在这种情况下没有正确实现标准)。


mus*_*cio 6

这是因为每一行都是作为一个整体来处理的,而不是逐列处理的。简化的顺序如下:

\n
    \n
  1. 获取匹配的行。
  2. \n
  3. 检索引用列的当前值。
  4. \n
  5. 根据要求更新列。
  6. \n
  7. 写回该行。
  8. \n
  9. 转到1。
  10. \n
\n

SQL 标准(至少是我可以访问的版本)规定了这些术语的行为(强调我的):

\n
\n
    \n
  1. 在调用由 T 的任何行更新引起的任何 <triggered action> 之前,对 T[able] 的每一行评估 S[et]C[lause]。
  2. \n
  3. 在更新 T 的任何行之前,将针对 T 的每一行有效评估S[et]C[lause]L[ist] 中包含的每个 <set Clause> 的 <update source> 。
  4. \n
  5. 对于每个主题行,通过复制主题行并按照 SCL 中包含的每个 <set Clause> 的指定,通过应用子条款 14.15 的一般规则 \xe2\x80\x9c<set Clause List> 更新它来构造候选新行。 \xe2\x80\x9d。
  6. \n
\n
\n