使用 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用法上的区别?