6

以下查询返回 2036 行:

SELECT "FooUID" from "Foo" f
LEFT JOIN "Bar" b ON f."BarUID" = b."BarUID"
WHERE f."BarUID" IS NOT NULL AND b."BarUID" IS NULL

但是下面的语句只更新了 1870 行:

UPDATE "Foo" f1 set "BarUID" = 'aNewUID'
WHERE f1."FooUID" IN (
   SELECT f2."FooUID" from "Foo" f2
   LEFT JOIN "Bar" b ON f2."BarUID" = b."BarUID"
   WHERE f2."BarUID" IS NOT NULL AND b."BarUID" IS NULL
)

这怎么可能?

编辑 1:第一个查询继续返回 166 行,第二个继续更新 0 行。

编辑2:

在下面,嵌套查询返回包含 UID 的行,但外部查询返回 0 行。

SELECT * from "Foo" f1
WHERE f1."FooUID" = (
   SELECT f2."FooUID" FROM "Foo" f2
   LEFT JOIN "Bar" b ON f2."BarUID" = b."BarUID"
   WHERE f2."BarUID" IS NOT NULL AND b."BarUID" IS NULL
   LIMIT 1
)

我疯了吗?

编辑 3:

@wildplasser提供的以下语句成功更新了剩余的 166 行:

UPDATE "Foo" ff
SET "BarUID" = 'aNewUID'
WHERE ff."BarUID" IS NOT NULL
AND NOT EXISTS (
   SELECT * FROM "Bar" bb
   WHERE bb."BarUID"= ff."BarUID"
)

但是,我仍然不明白为什么原版没有接他们。如果嵌套查询选择了 166"FooUID"秒,为什么它们不能使用 匹配到"Foo"表中的行IN

编辑 4:我想得越多,这个背景可能很重要:

这一切都发生在最近从另一台克隆的数据库服务器上。我与进行克隆的 IT 人员进行了交谈,结果发现他没有关闭在原始数据库之上运行的应用程序,然后才将其关闭以进行克隆。这意味着数据库很可能在事务中被关闭(我不知道这有多不优雅)。是否有可能数据库中的某些内容处于损坏状态,导致我看到这些幻像行?

不幸的是,我无法再复制它,因为运行了 wildplasser 的修复程序。原始数据库(再次启动并为应用程序提供服务)没有我试图在副本上修复的任何无效数据,更不用说我目睹的恶作剧的任何痕迹。

我应该提一下,在运行修复程序之前,我将问题简化为最基本的荒谬:我首先从编辑 2中FooUID的嵌套查询中选择了仍然返回 0 行。FooFooUID

4

1 回答 1

2

如果你用 NOT EXIST 重写它会发生什么,比如

UPDATE Foo ff
SET baruid = 'aNewUID'
WHERE ff.baruid IS NOT NULL
AND NOT EXISTS (SELECT * FROM bar bb
    WHERE bb.baruid = ff.baruid
    );

对我来说看起来比选择外连接的肢腿要干净得多。

于 2011-09-11T20:26:41.723 回答