left join on ...and ... 与left join on ... where.. 的区别

create table UserAccount
(
UID int,
UName varchar(50),
JoinDate datetime
)


insert into UserAccount values(1,'Jimmy','2006-10-3')
insert into UserAccount values(2,'Jack','2006-10-25')
insert into UserAccount values(3,'Mike','2006-11-13')
insert into UserAccount values(4,'Tom','2006-9-5')


create table ChargeHistory(UId int,ChargeDate datetime,Amount int)

insert into ChargeHistory values(1,'2007-3-1',50)
insert into ChargeHistory values(1,'2007-2-15', 30)
insert into ChargeHistory values(2,'2007-2-1' ,40)
insert into ChargeHistory values(3,'2007-1-15' ,60)
insert into ChargeHistory values(2,'2007-1-15' ,50)
insert into ChargeHistory values(3,'2007-1-1' ,100)
insert into ChargeHistory values(1,'2006-12-20' ,60)


select * from UserAccount
select * from ChargeHistory

1
Jimmy 2006-10-03 00:00:00.000 2
Jack 2006-10-25 00:00:00.000 3
Mike 2006-11-13 00:00:00.000 4
Tom 2006-09-05 00:00:00.000

1
2007-03-01 00:00:00.000 50 1
2007-02-15 00:00:00.000 30 2
2007-02-01 00:00:00.000 40 3
2007-01-15 00:00:00.000 60 2
2007-01-15 00:00:00.000 50 3
2007-01-01 00:00:00.000 100 1
2006-12-20 00:00:00.000 60



假设有一个游戏帐户充值网站

系统内有两个表

UserAccount

UID
UName
JoinDate

1
Jimmy
2006-10-3

2
Jack
2006-10-25

3
Mike
2006-11-13

4
Tom
2006-9-5



ChargeHistory

UId
ChargeDate
Amount

1
2007-3-1
50

1
2007-2-15
30

2
2007-2-1
40

3
2007-1-15
60

2
2007-1-15
50

3
2007-1-1
100

1
2006-12-20
60



1. 建表并填充数据

2. 完成如下操作:

A. 查询用户名为mike的充值记录,包含如下列

UName,UId,JoinDate,ChargeDate,Amount

B. 查询用户Id为1共充值多少金额.包含

UName,UId,JoinDate,Amount

C. 统计每个用户的充值总额,结果如下

UId
UName
Amount
JoinDate

1
Jimmy
140
2006-10-3

2
Jack
90
2006-10-25

3
Mike
160
2006-11-13

4
Tom
Null
2006-9-5



select A.UID,A.UName,A.JoinDate,B.ChargeDate,B.Amount from UserAccount A
left join ChargeHistory B on A.UID=B.UID and a.uname='mike' 这里的结果是:不是我们想要的结果因为:


--无论是left join 还是right join 的时候 on 后面的只允许是两个表中的关联字段,多个的话使用and连接,如果你写了某一个表的条件在里面,就像上面的例子,其实a.uname='mike'是不起作用的。所以在使用left join 和right join的时候需要注意,如果不是两个表的关联字段都需要写在where语句的后面。


Jimmy 2006-10-03 00:00:00.000 NULL NULL 2
Jack 2006-10-25 00:00:00.000 NULL NULL 3
Mike 2006-11-13 00:00:00.000 2007-01-15 00:00:00.000 60 3
Mike 2006-11-13 00:00:00.000 2007-01-01 00:00:00.000 100 4
Tom 2006-09-05 00:00:00.000 NULL NULL








select A.UID,A.UName,A.JoinDate,B.ChargeDate,B.Amount from UserAccount A
left join ChargeHistory B on A.UID=B.UID where A.UNAME='Mike'所以这里要使用where .where是left join 后筛选结果.

结果:

Mike 2006-11-13 00:00:00.000 2007-01-15 00:00:00.000 60 3
Mike 2006-11-13 00:00:00.000 2007-01-01 00:00:00.000 100 4

--但是inner join 是选择符合条件的数据出来
select A.UID,A.UName,A.JoinDate,B.ChargeDate,B.Amount from UserAccount A
inner join ChargeHistory B on A.UID=B.UID and a.uname='mike'

--group by 的操作:
--有函数存在 :sum,count,min,avg,max
--slecect多少个字段,group by 多少个字段
select A.UID,A.UName,A.JoinDate,sum(B.amount) from UserAccount A left join ChargeHistory B ON A.uID=B.UID WHERE A.UID=1
group by a.uid,A.UName,A.JoinDate

--这里还要注意 having的用法:是用来在group by 后再筛选数据的
select A.UID,A.UName,A.JoinDate,sum(B.amount) from UserAccount A left join ChargeHistory B ON A.uID=B.UID
group by a.uid,A.UName,A.JoinDate
having A.UID=1
<think> 我们正在讨论的是INNER JOINON ... ANDWHERE区别。根据用户的问题,用户想知道在INNER JOIN中,将条件放在ONAND后面和放在WHERE子句中是否相同。 回顾之前的引用,特别是引用[1]和引用[5]: 引用[1]提到:在INNER JOIN中,使用ON条件和使用WHERE条件在结果上是相同的,并且指出在大多数情况下性能也相同。 引用[5]也指出:在INNER JOIN中,条件写在ON子句和WHERE子句是等效的。 但是,我们需要更详细地解释为什么相同,以及是否有特殊情况。 原因分析: 1. 对于INNER JOIN,连接操作的本质是求两个表的交集。无论将条件放在ONAND后面还是WHERE子句中,最终结果都是只返回满足所有条件的行。 2. 在INNER JOIN中,数据库优化器会识别ON子句中的条件和WHERE子句中的条件,并生成相同的执行计划。因此,性能通常没有差异。 然而,注意:虽然结果相同,但在语义上有所区别: - ON子句中的条件用于指定两个表如何连接(即连接条件)。 - WHERE子句中的条件用于对连接后的结果进行过滤。 但在INNER JOIN中,由于连接条件不满足的行会被排除,所以即使将本该属于连接条件的条件放在WHERE子句中,结果也不会包含那些不满足连接条件的行。同样,如果将一个本属于过滤条件的条件放在ON子句中,由于INNER JOIN的特性,它也会起到过滤作用,因为不满足ON条件的数据行根本不会出现在结果中。 举例说明(使用引用[1]的示例): 假设我们有两个表:employees(员工表)和departments(部门表)。 查询1:使用INNER JOIN ON ... AND ```sql SELECT employees.employee_name, departments.department_name FROM employees INNER JOIN departments ON employees.department_id = departments.department_id AND employees.salary > 5000; ``` 查询2:使用INNER JOIN ON ... WHERE ```sql SELECT employees.employee_name, departments.department_name FROM employees INNER JOIN departments ON employees.department_id = departments.department_id WHERE employees.salary > 5000; ``` 这两个查询的结果是相同的。因为: - 在查询1中,连接条件包括两个:部门ID相等且员工工资大于5000。只有同时满足这两个条件的行才会被返回。 - 在查询2中,连接条件只有部门ID相等,然后对连接后的结果过滤出工资大于5000的行。 但是,由于是内连接,在连接时,如果某个员工的部门ID匹配但工资不满足>5000,那么在查询1中该员工不会出现在连接结果中;同样在查询2中,虽然在连接时该员工因为部门ID匹配而出现在连接结果中,但随后会被WHERE条件过滤掉。所以最终结果是一样的。 结论:在INNER JOIN中,ON ... ANDWHERE在结果上是等效的。但是,为了提高可读性,通常将连接条件放在ON子句中,而将过滤条件放在WHERE子句中。这样,ON子句专门用于描述表之间的关联关系,WHERE子句用于对结果集进行过滤。这种写法在连接多个表时更清晰。 引用支持: 引用[1]指出:在INNER JOIN中,两种方式的结果相同,并且提到了可读性和可维护性的最佳实践[^1]。 引用[5]也表明INNER JOIN中条件写在ONWHERE是等效的[^5]。 因此,回答用户的问题:在INNER JOIN中,ON ... ANDON ... WHERE(即条件放在ON子句的AND后面还是放在WHERE子句)在结果上是相同的,但建议按语义区分。 相关问题: 1.LEFT JOIN中,ON ... ANDWHERE是否也一样?为什么? 2. 多表INNER JOIN时,将过滤条件放在不同的位置(ON子句或WHERE子句)会对结果产生什么影响? 3. 从性能角度,INNER JOIN中条件放在ONWHERE区别吗? </think> ### INNER JOIN中`ON ... AND``WHERE`的本质对比 在**INNER JOIN**场景下,`ON ... AND`和`WHERE`的区别主要体现在语义和可读性上,**最终查询结果是完全相同的**,原因如下: #### 一、等效性原理 | **特性** | `ON ... AND` | `WHERE` | |----------------|-------------------------------------------|------------------------------------------| | **过滤逻辑** | 连接过程中过滤匹配行 | 连接完成后过滤结果集 | | **结果集** | 仅返回满足连接条件+AND条件的行 | 仅返回满足连接条件+WHERE条件的行 | | **性能** | 优化器通常生成相同执行计划[^1] | 优化器通常生成相同执行计划[^1] | > **核心结论**: > 对于INNER JOIN,以下两种写法**结果完全等价**: > ```sql > -- 写法1: ON ... AND > SELECT * > FROM table1 > INNER JOIN table2 > ON table1.id = table2.id > AND table1.status = 1; -- 条件写在ON子句 > > -- 写法2: WHERE > SELECT * > FROM table1 > INNER JOIN table2 > ON table1.id = table2.id > WHERE table1.status = 1; -- 条件写在WHERE子句 > ``` > 因为INNER JOIN本身要求**必须同时满足连接条件和过滤条件**,否则记录会被丢弃[^1][^5]。 #### 二、差异详解(仅语义层面) 1. **语义区别** - `ON ... AND`:强调条件是**连接过程的一部分** ```sql INNER JOIN departments ON emp.dept_id = dept.id AND dept.budget > 100000 -- 暗示此条件连接相关 ``` - `WHERE`:强调条件是**结果集的独立过滤** ```sql INNER JOIN departments ON emp.dept_id = dept.id WHERE dept.budget > 100000 -- 明确为独立过滤条件 ``` 2. **可读性建议** - 单表过滤条件优先用`WHERE`(如`employees.salary > 5000`[^1]) - 多表关联条件必须用`ON`(如`employees.department_id = departments.department_id`[^1]) - **混合场景规范写法**: ```sql SELECT emp.name, dept.name FROM employees emp INNER JOIN departments dept ON emp.dept_id = dept.id -- 连接条件放ON AND dept.type = 'IT' -- 右表过滤放ON(可选) WHERE emp.salary > 5000 -- 左表过滤放WHERE ``` #### 三、特殊场景验证 自连接查询(同一表连接)同样遵循此规则: ```sql -- 自连接等效示例 SELECT child.id, parent.title FROM areas AS child INNER JOIN areas AS parent ON child.pid = parent.id -- 连接条件 AND parent.title = '济宁市'; -- 等效于WHERE过滤[^4] ``` > 无论条件写在`ON ... AND`还是`WHERE`,结果均相同[^4]。 #### 四、最佳实践建议 1. **优先用`WHERE`** 单表过滤条件(如`employees.salary > 5000`[^1])置于`WHERE`子句,语义更清晰。 2. **复杂连接用`ON ... AND`** 当右表过滤条件连接逻辑强相关时(如`dept.budget > 100000`),可放入`ON`子句。 3. **避免混淆写法** 不要将连接条件(如`a.id=b.id`)误写入`WHERE`,这可能导致笛卡尔积[^3]。 > ⚠️ **重要提醒**: > 此等效性**仅适用于INNER JOIN**。在`LEFT JOIN`中二者行为完全不同([见之前的对比](请参考您提供的历史回答))。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值