使用 INNER JOIN 和 NOT EXISTS 访问 INSERT 语句给出错误结果

Posted

技术标签:

【中文标题】使用 INNER JOIN 和 NOT EXISTS 访问 INSERT 语句给出错误结果【英文标题】:Access INSERT statement using INNER JOIN with NOT EXISTS gives wrong result 【发布时间】:2011-06-27 19:04:25 【问题描述】:

我有一个 Access .mdb 数据库。有两个结构相同的表:Prices 和 tmpPrices。每个表都有三列:[截至日期标准](日期/时间)、价格(双精度)、CUSIP(文本,255 个字符)。 tmpPrices 包含要添加到价格中的新记录。我有两个 SQL 查询来从 tmpPrices 更新价格,一个使用 WHERE 联接,另一个使用 INNER JOIN。

以下版本 A 可以正常工作:

INSERT INTO [Prices] SELECT * FROM [tmpPrices] WHERE NOT EXISTS 
(SELECT * from [Prices]
  WHERE ([Prices].[As of date std] = [tmpPrices].[As of date std])
  AND ([Prices].CUSIP = [tmpPrices].CUSIP));

而此版本 B 不起作用:

INSERT INTO [Prices] SELECT * FROM [tmpPrices] WHERE NOT EXISTS
(SELECT  [Prices].* FROM [Prices] INNER JOIN [tmpPrices] ON 
   ([Prices].[As of Date std] = [tmpPrices].[As of Date std]) 
   AND ([Prices].CUSIP = [tmpPrices].CUSIP));

两个子查询给出相同的结果:来自 tmpPrices 的记录子集已经存在于价格中。

如果不是我必须更新其他表并且使用版本 A 更新另一个表大约需要 45 分钟,但使用版本 B 只是其中的一小部分,并且它似乎可以正常工作,那么使用版本 A 并没有太大关系.所以我想了解这里发生了什么。

【问题讨论】:

【参考方案1】:

正如@devsh 建议的那样,LEFT JOIN 绝对是要走的路,但您不需要使用子查询。我在 Access 的查询设计器中构建了它,它在 Access 2003 中与您描述的表一起工作。我确实重命名了 [As of date std] 以消除空格。

INSERT INTO Prices ( As_of_Date_std, Price, CUSIP)
SELECT t.As_of_Date_std, t.Price, t.CUSIP
FROM
    tmpPrices AS t
    LEFT JOIN Prices AS p
    ON (t.As_of_Date_std = p.As_of_Date_std) AND (t.CUSIP = p.CUSIP)
WHERE (((p.As_of_Date_std) Is Null));

【讨论】:

您的解决方案简洁明了,执行速度非常快,即使在有 150 万行的表上也是如此。【参考方案2】:

第二个查询不起作用,因为查询的选择部分(您尝试从中插入)和包含的子查询之间没有链接。如果您确实想使用该格式进行插入,您可以这样做:

INSERT INTO [Prices]
SELECT [As of Date], Price, CUSIP
FROM 
(SELECT tmpPrices.[As of Date std], tmpPrices.[Price], tmpPrices.[CUSIP]
FROM tmpPrices LEFT JOIN Prices ON
([Prices].[As of date std] = [tmpPrices].[As of date std]) AND ([Prices].CUSIP = [tmpPrices].CUSIP)) WHERE Prices.[As of date std] is null)

【讨论】:

当我尝试运行它时,您的回答给了我一个循环参考。我正在使用 hansup 的解决方案,但我认为 LEFT JOIN 非常聪明。很遗憾,我没有足够的积分来投票。【参考方案3】:

A 需要很长时间,因为它基本上是对价格中的每条记录进行 tmpPrices 的全表扫描,因为在子查询中没有定义实际的连接。

让我们看看我们能否为您提供快速查询,满足您的需求。

tmpPrices 需要一个自动编号字段才能工作,我建议将其设置为 tmpPrices 的 pk。还有一个基于其他 3 个字段的唯一键,以防止 tmpPrices 中的重复(很确定您可以在 Access 中做到这一点)。

INSERT INTO [Prices] ([As of Date std],[Price],[CUSIP])
SELECT [As of Date std],[Price],[CUSIP] from tmpPrices where autoNumberID not in(
  SELECT autonumberID
  FROM tmpPrices 
  innerJoin prices on [Prices].[As of Date std] = [tmpPrices].[As of Date std] 
   AND [Prices].CUSIP = [tmpPrices].CUSIP
) query1

如果您在每次使用此更新价格时清除 tmpPrices 中的任何记录,这也将有助于保持速度。

【讨论】:

很遗憾,我无法使用您的解决方案,因为我不允许更改表格的结构。

以上是关于使用 INNER JOIN 和 NOT EXISTS 访问 INSERT 语句给出错误结果的主要内容,如果未能解决你的问题,请参考以下文章

SQL中inner join,outer join和cross join的区别

SQL中inner join,outer join和cross join的区别

关于SQL数据库中cross join 和inner join用法上的区别?

使用 LEFT JOIN 和 INNER JOIN 插入

SQL中inner joinouter join和cross join的区别

SQL中inner joinouter join和cross join的区别