ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 672|回复: 4

[求助] access查询语句求解释!

[复制链接]

TA的精华主题

TA的得分主题

发表于 2021-2-1 10:39 | 显示全部楼层 |阅读模式
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 lyzcl 于 2021-2-1 10:45 编辑

查询语句1:
SELECT Contacts.FirstName, Contacts.LastName
FROM Contacts
WHERE (((Contacts.FirstName) In (SELECT [FirstName] FROM [Contacts] As Tmp GROUP BY [FirstName],[LastName] HAVING Count(*)>1  And [LastName] = [Contacts].[LastName])))
ORDER BY Contacts.FirstName, Contacts.LastName;

结果(正确)如下:


查询语句2:
SELECT Contacts.FirstName, Contacts.LastName
FROM Contacts
WHERE (((Contacts.FirstName) In (SELECT [FirstName] FROM [Contacts] As Tmp GROUP BY [FirstName],[LastName] HAVING Count(*)>1  )))
ORDER BY Contacts.FirstName, Contacts.LastName;

结果(错误)如下:

为什么会出现这样的不同结果呢?2个查询语句的区别就在于加了“And [LastName] = [Contacts].[LastName]”这一段。不知道该怎么理解?
按我的理解,这2条查询语句都是先筛出一个tmp临时表,然后FirstName从这个tmp临时表里筛选,搞不清楚怎么能实现把LastName不同的记录给去掉的。

正确结果

正确结果
错误结果.png

TA的精华主题

TA的得分主题

发表于 2021-2-1 13:57 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本人的理解,请参考:
查询2,只是对firstname分组聚合运算,pete的count结果只有1个为3
而查询1多了个条件,聚合运算后pete的count结果有2个,分别为2(peet and moss)和1(peet and teeth),因为>1,所以 peet and teeth没有满足条件的记录就被去掉了。

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-2-1 20:17 | 显示全部楼层
ly 发表于 2021-2-1 13:57
本人的理解,请参考:
查询2,只是对firstname分组聚合运算,pete的count结果只有1个为3
而查询1多了个条 ...

感谢回复,我疑惑的有3点:
1. 查询2里面,GROUP BY [FirstName],[LastName] HAVING Count(*)>1 似乎已经是对[FirstName]和[LastName]2个字段进行聚合了,理应在tmp临时表里排除pete teeth(只有一行)的记录;
2. 查询1里面,And [LastName] = [Contacts].[LastName] 这段语句的作用是什么,得出的结果是什么,又是如何进一步与前面的语句共同作用的?
3. 无论查询1还是查询2,得到的tmp临时表都应该只有[FirstName] 一个字段,也就是说不管是否排除了pete teeth这个只有一行的记录,tmp表的内容都是annie,pete,sue这3条记录。再从中匹配[FirstName],查询1和查询2的结果应该都是一样的(都包含pete teeth)?

我尝试着把in后面的字段截取出来单独运行,
1)当运行SELECT [FirstName] FROM [Contacts] As Tmp GROUP BY [FirstName],[LastName] HAVING Count(*)>1 时,得到annie,pete,sue这3条记录的tmp临时表(如果加上count(*) as count后,count字段显示pete moss的计数为2,并排除了pete teeth,说明这段语句是对2个字段的聚合)。
2)当运行SELECT [FirstName] FROM [Contacts] As Tmp GROUP BY [FirstName],[LastName] HAVING Count(*)>1  And [LastName] = [Contacts].[LastName]时,access却提示我输入参数,这是怎么回事?

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-2-5 23:35 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
自己查了些资料,对这个问题有所理解,自问自答吧:
这个问题来源于access查询向导生成的重复项查询,当时看不明白,几年前就在这里发过帖询问,没有答复。最近又捡起access,还是对这个问题绕不过去。又通过SQL查询语句的角度提问,还是没有满意的答复。可能是问题太初级,解释起来又费劲吧。我在网上搜索,通过“access重复性查询”搜到了一篇文章,里面提到access重复性查询向导生成的SQL语句不容易理解,另外给出了用INNER JOIN方式的SQL查询,容易看懂。文章链接如下:
https://blog.csdn.net/gracexu/article/details/2134309
该文章没有直接对access生成的SQL语句进行解读,但提到了之所以不易理解,是因为涉及到了“子查询”。所以我又看了些有关“SQL子查询”的内容。终于在一定程度上理解了。下面是我的理解:

查询1是access生成的SQL语句:SELECT Contacts.FirstName, Contacts.LastName
FROM Contacts
WHERE (((Contacts.FirstName) In (SELECT [FirstName] FROM [Contacts] As Tmp GROUP BY [FirstName],[LastName] HAVING Count(*)>1  And [LastName] = [Contacts].[LastName])))
ORDER BY Contacts.FirstName, Contacts.LastName;
之前我不理解,是因为对“SQL关联子查询”的运行方式不了解。按照初级的编程语言的理解,我想当然的以为这条SQL语句应该先运行IN()里面的内容,返回结果用于上层Where()语句,最后再把返回结果应用于最外层的select语句。这样去理解,会遇到无法解决的困惑。
而“SQL关联子查询”真正的运行方式是这样的:外层先把查询结果每次输送一条给子查询。这个例子里,外层查询出的是全部记录,首先把第一条记录(Annie,matter)传输给子查询,此时的子查询中,SELECT [FirstName] FROM [Contacts] As Tmp GROUP BY [FirstName],[LastName] HAVING Count(*)>1  And [LastName] = [Contacts].[LastName]语句首先有了限定条件:[LastName]=“matter”,又对[FirstName],[LastName]进行聚合,实际上的结果只有“Annie”这一条记录。这个结果输送给上一层,相当于WHERE “Annie” In {"Annie"},语句成立,外层查询SELECT Contacts.FirstName, Contacts.LastName
FROM Contacts成功输出了第一条查询结果(Annie,matter)。
然后第二条记录、第三条记录……依次执行。当遇到(pete,teeth)这条记录时,子查询SELECT [FirstName] FROM [Contacts] As Tmp GROUP BY [FirstName],[LastName] HAVING Count(*)>1  And [LastName] = "teeth"由于聚合的结果不大于1,返回的结果是空。所以对外层查询来说,(pete,teeth)这条记录就被排除了。

查询2是我改的,把子查询中我当初理解不了的And [LastName] = [Contacts].[LastName]去掉了。
SELECT Contacts.FirstName, Contacts.LastName
FROM Contacts
WHERE (((Contacts.FirstName) In (SELECT [FirstName] FROM [Contacts] As Tmp GROUP BY [FirstName],[LastName] HAVING Count(*)>1  )))
ORDER BY Contacts.FirstName, Contacts.LastName;
这样一来,子查询和外层查询的关联就没有了。我不清楚整个SQL语句运行时是否还是每次由外层传递给子查询一条记录。不管如何,此时当遇到(pete,teeth)这条记录时,查询SELECT [FirstName] FROM [Contacts] As Tmp GROUP BY [FirstName],[LastName] HAVING Count(*)>1因为少了一个限制,聚合后返回给上层的结果应该是{Annie,Pete,Sue}而不再是空。所以就错误的输出了(pete,teeth)这条查询结果。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-23 10:32 , Processed in 0.028303 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表