使用另一条记录的同一列交换列值

时间:2011-12-01 09:58:41

标签: mysql sql

我有一个包含IDPositionName列的相当简单的表格。

ID  Position  Name
1   1         RecordX
2   3         RecordY
3   2         RecordZ

Position列用作以用户定义的顺序显示记录的索引,它应该是唯一的,不能低于1且不高于表中的记录数,在此情况3.该列不强制唯一性,因此暂时可以有2个具有相同Position的记录,但最终没有两个记录对于正确的程序工作应该具有相同的位置。 目前,为了交换两个记录的位置,我需要做3个查询,即:

  1. 找到其他记录的ID

  2. 更新当前记录的Position以匹配其他记录的Position

  3. 通过之前找到的Position更新其他记录的ID(由于暂时会有两条记录具有相同的Position,因此Position更新不是可能的。

  4. 我觉得应该有一种方法可以用更少的数据库轮次来完成这项工作,因此查询次数少于3次。我该如何处理这个问题?

3 个答案:

答案 0 :(得分:4)

单一“交换”操作......

SWAP(@old_pos,@ new_pos)

UPDATE
  my_table
SET
  position = CASE WHEN position = @old_pos THEN @new_pos ELSE @old_pos END
WHERE
  position IN (@old_pos, @new_pos)


但这并不容易扩展到交换操作表。这是因为它会尝试一次完成所有掉期,而事实上掉期必须以特定的顺序发生...


此外,如果要进行SWAP(@ id,@ new_pos),则需要对要更新的表执行子查询或自联接。 MySQL不喜欢这样,虽然有限制的方法,但它会使事情变得有点混乱......

UPDATE
  my_table
INNER JOIN
  (SELECT position AS old_pos, @new_pos AS new_pos FROM (SELECT position FROM my_table WHERE id = @id)) AS params
    ON my_table.position IN (params.old_pos, params.new_pos)
SET
  myTable.position = CASE WHEN position = old_pos THEN new_pos ELSE old_pos END

(我认为会起作用)


注意:

这两个都假设找到了@old_pos和@ new_pos,或@id和@new_pos,它没有检查,如果它们不存在,弄得一团糟。< / p>

这可以通过将其置于事务中来解决,如果ROW_COUNT()显示只更新了1条记录,则可以回滚。

答案 1 :(得分:1)

SET @new_pos_for_id_1:=3, @new_pos_for_id_3:=1;
UPDATE my_table
    JOIN (
        SELECT 1 as id, @new_pos_for_id_1 as new_position
        UNION ALL
        SELECT 3 as id, @new_pos_for_id_3 as new_position) as positions
    USING (id)
SET position = new_position

此查询可用于一次更改多行的位置。我喜欢@Dems&#39;解决方案。

UPD:

<强>解释

SELECT 1 as id, 3 as new_position
UNION ALL
SELECT 3 as id, 1 as new_position

是一个由两列组成的动态构造表:id, new_position其中每个id都映射到一个新的预期位置。我只是JOINmy_table字段上使用id的表格,并将my_table中的值替换为构造表格中的值。

答案 2 :(得分:0)

这可能适用于任何DBMS。

-- create some data
DROP TABLE ztable CASCADE;
CREATE TABLE ztable
    ( id integer NOT NULL PRIMARY KEY
    , val INTEGER 
    );      

INSERT INTO ztable(id,val) VALUES (1,1), (2,3), (3,2);
SELECT * FROM ztable;

UPDATE ztable t1
SET val=t2.val
FROM ztable t2
WHERE t1.id IN (2,3)
AND t2.id IN (2,3)
AND t1.id <> t2.id
    ;       
SELECT * FROM ztable;

结果:

CREATE TABLE
INSERT 0 3
 id | val 
----+-----
  1 |   1
  2 |   3
  3 |   2
(3 rows)

UPDATE 2
 id | val 
----+-----
  1 |   1
  2 |   2
  3 |   3
(3 rows)