在数据库中交换唯一的索引列值

我有一个数据库表,其中一个字段(不是主键)上有一个唯一的索引。现在我想将这个列下的值交换两行。这怎么能做到?我知道的两个黑客是:

  1. 删除两行并重新插入它们
  2. 用其他值更新行 然后交换并更新为实际值。

但我不想去这些,因为他们似乎不是解决问题的恰当方法。 任何人都可以帮我吗?

0
额外 编辑
意见: 9
重命名列?
额外 作者 MatBailie,

19 答案

GDAL user-friendliness is basically nonexistent, but hot damn does it ever work well. I wrote up this guide to my own georeferencing experiments a few years ago: http://mike.teczno.com/notes/flea-market-mapping.html

这有点过时,但基本要素在那里:找到图像和参考地图之间的匹配点(我现在推荐 http:// getlatlon。 com 支持 http://gorissen.info ),使用gdal_translate打开一个虚拟光栅,基本上完成了,因为生成的VRT文件可以转换为您选择的GeoTIFF或tile。

I'm doing a lot with this right now, including collaborating with Tim Waters on the excellent server-side Map Warper mentioned in this thread, so there may be some new stuff in the near future loosely based on some experiments I did in JS last year: http://mike.teczno.com/notes/canvas-warp.html

22
额外
米哈尔,非常感谢!我很好奇如何找到像素位置,并提到您使用了Photoshop的信息面板,这很有帮助。我想我可以逃脱使用一阶变换。感谢所有的信息!
额外 作者 TiTi,
QGIS 1.5刚刚发布并正在查看更新日志( qgis.org/ en/component/content/article/108.html )我注意到“将GDAL栅格工具插件包含到QGIS核心中”。
额外 作者 TiTi,

我知道两种基于网络的解决方案值得一看:

我很确定Tim Waters公开源代码,因此即使这些特定工​​具不适合您的需求,查看其源代码也可能会给您一些见解。

对不起,我不能发布多个外部链接,因为我显然比信誉好。

10
额外
你现在应该可以添加更多的链接:)
额外 作者 Greg,
有趣的是,我前几天再次看着MapWarper。源代码位于GitHub上: github.com/timwaters/mapwarper
额外 作者 cynicalman,

我发现QGis的georeferencer对于点击工具来说是相当不错的。我写了一个小小的指南 - 使用QGIS进行图像地理配准 - 源特定的,但通过所有步骤,你需要得到一个任意的地图到QGis。

7
额外

我发现QGis的georeferencer对于点击工具来说是相当不错的。我写了一个小小的指南 - 使用QGIS进行图像地理配准 - 源特定的,但通过所有步骤,你需要得到一个任意的地图到QGis。

7
额外

您也可以在 MapWindow 中使用图像整流器插件。 它使用增强型4点或6点算法。

2
额外

您还可以在 MapWindow 中使用图像整流器插件。 它使用增强型4点或6点算法。

2
额外

由于您使用的是空中图像:您是否需要正射校正?在这种情况下,我认为ILWIS将是你最好的选择,尽管GRASS也支持它(尽管我自己并没有尝试过)。

ILWIS的工作流程如下所述: http://spatial-analyst.net/PDF/TN_Ortofoto_in_ILWIS.pdf

2
额外
GRASS正射校正工作流程可在此处找到: grassbook.org - >左侧菜单 - >样本章节: - >天线+ Ortho(PDF)
额外 作者 Dag Haavi Finstad,

OpenEV随FWTools一起提供,对我来说似乎还可以,但我可以轻松地将300 MB图像加载到QGIS中并在那里处理它们。所以我可以推荐它只是偶尔使用。

http://OpenEV.sourceforge.net

包括NITF

并用GDAL构建

1
额外

如果您有或可以为图像创建* .geom文件,则可以使用orthoigen gdal来对图像进行准确定位。

1
额外

我也认为#2是最好的选择,尽管我会确保在交易中包装它,以防中间更新中出现问题。

另一种方法(因为您要求)使用不同的值更新唯一索引值将会将行中的所有其他值更新为另一行的值。这样做意味着您可以单独保留唯一索引值,并最终获得所需的数据。但要小心,以防其他表在DB中引用此表时,DB中的所有关系都保持不变。

0
额外

对于Oracle,有一个选项DEFERRED,但您必须将其添加到您的约束。

SET CONSTRAINT emp_no_fk_par DEFERRED; 

要推迟在整个会话期间可延期的所有约束,可以使用ALTER SESSION SET constraints = DEFERRED语句。

0
额外

Oracle具有延迟完整性检查功能,可以完全解决这个问题,但它在SQL Server或MySQL中都不可用。

0
额外

在SQL Server中,MERGE语句可以更新通常会破坏唯一键/索引的行。 (刚刚测试过,因为我很好奇。)

但是,您必须使用临时表/变量来为必需的行提供MERGE。

0
额外

这里的魔术字是 DEFERRABLE

DROP TABLE ztable CASCADE;
CREATE TABLE ztable
    ( id integer NOT NULL PRIMARY KEY
    , payload varchar
    );
INSERT INTO ztable(id,payload) VALUES (1,'one' ), (2,'two' ), (3,'three' );
SELECT * FROM ztable;


    -- This works, because there is no constraint
UPDATE ztable t1
SET payload=t2.payload
FROM ztable t2
WHERE t1.id IN (2,3)
AND t2.id IN (2,3)
AND t1.id <> t2.id
    ;
SELECT * FROM ztable;

ALTER TABLE ztable ADD CONSTRAINT OMG_WTF UNIQUE (payload)
    DEFERRABLE INITIALLY DEFERRED
    ;

    -- This should also work, because the constraint 
    -- is deferred until "commit time"
UPDATE ztable t1
SET payload=t2.payload
FROM ztable t2
WHERE t1.id IN (2,3)
AND t2.id IN (2,3)
AND t1.id <> t2.id
    ;
SELECT * FROM ztable;

结果:

DROP TABLE
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "ztable_pkey" for table "ztable"
CREATE TABLE
INSERT 0 3
 id | payload
----+---------
  1 | one
  2 | two
  3 | three
(3 rows)

UPDATE 2
 id | payload
----+---------
  1 | one
  2 | three
  3 | two
(3 rows)

NOTICE:  ALTER TABLE / ADD UNIQUE will create implicit index "omg_wtf" for table "ztable"
ALTER TABLE
UPDATE 2
 id | payload
----+---------
  1 | one
  2 | two
  3 | three
(3 rows)
0
额外
这在MySQL中工作吗?
额外 作者 Marco Demaio,
@MarcoDemaio我不知道。恐怕不会:因为mysql不允许自联接更新,所以我认为它确实存在脏读。但你可以尝试...
额外 作者 wildplasser,
干净,简单,工作很好,谢谢你:)
额外 作者 Aldos,

我也有同样的问题。这是我在PostgreSQL中提出的方法。在我的情况中,我的唯一索引是一个序列值,在我的行上定义了明确的用户顺序。用户将在网络应用程序中随机播放行,然后提交更改。

我打算添加一个“之前”触发器。在该触发器中,只要我的唯一索引值更新,我会查看是否有其他行已经保存了我的新值。如果是这样,我会给他们我以前的价值,并有效地窃取他们的价值。

我希望PostgreSQL将允许我在前触发器中进行这种洗牌。

我会回复并让你知道我的里程。

0
额外

假设你知道要更新的两行的PK ...这在SQL Server中起作用,不能用于其他产品。 SQL(应该是)在语句级别是原子的:

CREATE TABLE testing
(
    cola int NOT NULL,
    colb CHAR(1) NOT NULL
);

CREATE UNIQUE INDEX UIX_testing_a ON testing(colb);

INSERT INTO testing VALUES (1, 'b');
INSERT INTO testing VALUES (2, 'a');

SELECT * FROM testing;

UPDATE testing
SET colb = CASE cola WHEN 1 THEN 'a'
                WHEN 2 THEN 'b'
                END
WHERE cola IN (1,2);

SELECT * FROM testing;

所以你会从:

cola    colb
------------
1       b
2       a

至:

cola    colb
------------
1       a
2       b
0
额外
这在MySQL中并不适用于我。
额外 作者 activout.se,

我认为你应该去寻求解决方案2.在我知道的任何SQL变体中没有“交换”函数。

如果你需要定期做这些,我建议解决方案1,这取决于软件的其他部分如何使用这些数据。如果你不小心,你可能会遇到锁定问题。

但简而言之:除了您提供的解决方案之外,没有其他解决方案。

0
额外

还有另一种适用于SQL Server的方法:在您的UPDATE语句中使用临时表连接到它。

这个问题是由两行同时具有相同值引起的引起的,但是如果您同时更新两行(对于它们的新唯一值),则不存在违反约束的情况。

伪代码:

-- setup initial data values:
insert into data_table(id, name) values(1, 'A')
insert into data_table(id, name) values(2, 'B')

-- create temp table that matches live table
select top 0 * into #tmp_data_table from data_table

-- insert records to be swapped
insert into #tmp_data_table(id, name) values(1, 'B')
insert into #tmp_data_table(id, name) values(2, 'A')

-- update both rows at once! No index violations!
update data_table set name = #tmp_data_table.name
from data_table join #tmp_data_table on (data_table.id = #tmp_data_table.id)

感谢Rich H为此技术。 - 马克

0
额外
可能会有点老,但我试图为我的Silverlight应用程序做一个'重新排序'页面,因为客户希望按特定顺序对他们的报告进行排序 - 我添加了一个排序列,但由于它是一个唯一的密钥,我是无法更新它。我结束了使用表变量,但原则是一样的(我不喜欢临时表很多老实说!)。感谢这个想法:)
额外 作者 Charleh,

我通常会想到一个值,绝对没有我的表中的索引可能。通常 - 对于独特的列值 - 这非常简单。例如,对于“位置”列的值(有关多个元素的顺序的信息),它是0。

然后你就可以值一个复制到一个变量,从您的变量值B,然后设定值B更新。两个疑问,我知道有没有更好的解决办法,但。

0
额外