我有一个包含ID
,Position
,Name
列的相当简单的表格。
ID Position Name
1 1 RecordX
2 3 RecordY
3 2 RecordZ
Position
列用作以用户定义的顺序显示记录的索引,它应该是唯一的,不能低于1且不高于表中的记录数,在此情况3.该列不强制唯一性,因此暂时可以有2个具有相同Position
的记录,但最终没有两个记录对于正确的程序工作应该具有相同的位置。
目前,为了交换两个记录的位置,我需要做3个查询,即:
找到其他记录的ID
更新当前记录的Position
以匹配其他记录的Position
通过之前找到的Position
更新其他记录的ID
(由于暂时会有两条记录具有相同的Position
,因此Position
更新不是可能的。
我觉得应该有一种方法可以用更少的数据库轮次来完成这项工作,因此查询次数少于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都映射到一个新的预期位置。我只是JOIN
在my_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)