在某些行上交换列?

MEC*_*ECU 1 mysql

我有一个大约 106k 行的表,其中大约 11k 行交换了 2 列中的值。我想运行一个查询来修复它,但我认为我不能这样做:

UPDATE `game` 
SET `homescore`=`awayscore`, `awayscore`=`homescore` 
WHERE (`awayscore`>`homescore` AND `winner`=`hometeam`) OR (`awayscore`<`homescore` AND `winner`=`awayteam`);
Run Code Online (Sandbox Code Playgroud)

或者我可以吗?我担心这两个分数最终会得到相同的值。

另外,请验证我的查询是否符合我的意图:

我需要在记录的获胜者(这是正确的)与记录的分数不匹配的行上交换主客场得分(他们被现已修复的编码错误意外交换)说谁是获胜者(得分更高的球队) )。

ype*_*eᵀᴹ 6

在任何体面的 RDBMS(例如 Postgres、SQL-Server、Oracle、DB2)中,简单的方法都可以正常工作并交换两列的值:

UPDATE game 
SET homescore = awayscore, 
    awayscore = homescore 
WHERE (awayscore > homescore AND winner = hometeam) 
   OR (awayscore < homescore AND winner = awayteam) ;
Run Code Online (Sandbox Code Playgroud)

在 MySQL 中,它不会按预期工作!您必须使用某种技巧,例如:

UPDATE game 
SET homescore = (@tmp := homescore),
    homescore = awayscore, 
    awayscore = @tmp 
WHERE (awayscore > homescore AND winner = hometeam) 
   OR (awayscore < homescore AND winner = awayteam) ;
Run Code Online (Sandbox Code Playgroud)

您还可以在表中再添加一两列,使用它们进行交换,然后删除它们,但效率不会很高。更好的方法是使用另一个(临时)表:

CREATE TABLE temp_swap
( pk INT NOT NULL         -- whatever datatype the Primary Key of your table is
, homescore INT           -- INT or FLOAT or DECIMAL
, awayscore INT           -- whatever the two columns are
, PRIMARY KEY (pk)
) ;
Run Code Online (Sandbox Code Playgroud)

复制要在那里交换的值:

INSERT INTO temp_swap
  (pk, homescore, awayscore)
SELECT pk, homescore, awayscore 
FROM game 
WHERE (awayscore > homescore AND winner = hometeam) 
   OR (awayscore < homescore AND winner = awayteam) ;
Run Code Online (Sandbox Code Playgroud)

然后返回,交换,进入表:

UPDATE game AS g
  JOIN temp_swap AS t
    ON t.pk = g.pk
SET g.homescore = t.awayscore, 
    g.awayscore = t.homescore ;

DROP TABLE temp_swap ;
Run Code Online (Sandbox Code Playgroud)


a1e*_*x07 5

您的担忧是有效的,mysql 文档

如果在表达式中访问要更新的表中的列,UPDATE 将使用该列的当前值。例如,以下语句将 col1 设置为比其当前值大 1: UPDATE t1 SET col1 = col1 + 1;

以下语句中的第二个赋值将 col2 设置为当前(更新后的) col1 值,而不是原始 col1 值。结果是 col1 和 col2 具有相同的值。此行为不同于标准 SQL。
更新 t1 SET col1 = col1 + 1, col2 = col1;

为了解决这个问题,我建议添加 2 列,比如说homescore_oldawayscore_old,复制homescoreawayscore在那里,然后你UPDATE在右侧分配中使用新添加的列。完成后,您可以删除old列。也可以只使用一列额外的列,但同样,文档指出,

单表 UPDATE 分配通常从左到右进行评估。

在我的理解中,“一般”与“总是”不同。