dml中的and使用误区

本文揭示了一个在MySQL中使用UPDATE语句时容易忽略的问题:在SET子句中错误地使用逻辑运算符AND,这可能导致数据更新失败但系统却显示更新成功的情况。通过实际案例展示了这种错误用法的危害,并给出了正确的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下午刚刚在一个jira变更中的遇到问题,非常容易产生误使用,产生比较大的危害。大家看下。非常简单的一条SQL:

mysql> update order_original set audit_status=3 and is_queue=1 where id=16682331;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0


很快就执行完了。但是,大家留意到没? Changed: 0 ,即虽然Rows matched: 1,确实有 id=16682331这一行,但是没有更新成功。这时,很多人肯定想到,这里肯定就是已经被更新过了啊。我们来看下:

mysql> select audit_status,is_queue from order_original where id=16682331;
+--------------+----------+
| audit_status | is_queue |
+--------------+----------+
| 1 | 1 |
+--------------+----------+
1 row in set (0.00 sec)


是不是很奇怪,并不是我们想要的结果。OK,我们把SQL改变一下写法:

mysql> update order_original set audit_status=3, is_queue=1 where id=16682331;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0


注意,是不是已经是Changed: 1 ?我们实例再查一下:

mysql> select audit_status,is_queue from order_original where id=16682331;
+--------------+----------+
| audit_status | is_queue |
+--------------+----------+
| 3 | 1 |
+--------------+----------+
1 row in set (0.00 sec)


确实数据update成功了。到这里大家应该明白了吧。如果还不明白,我们再做一个更明显的实验,帮忙看清本质的原因:

mysql> create table test(a int,b int,c int);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test values(1,2,3);
Query OK, 1 row affected (0.00 sec)

mysql> update test set b=99 and c=3 where a=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from test;
+------+------+------+
| a | b | c |
+------+------+------+
| 1 | 1 | 3 |
+------+------+------+
1 row in set (0.00 sec)

mysql> update test set b=99 and c=5 where a=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from test;
+------+------+------+
| a | b | c |
+------+------+------+
| 1 | 0 | 3 |
+------+------+------+
1 row in set (0.01 sec)


即在update中,set 列=值,这个等号后面把and看成一个位运算,当后面的结果存在或正确时(set b=99 and c=3),那就是set 列=1,错误或不存在时(set b=99 and c=5)就是0。

因此,这个SQL的写法的危害是极大的,如果一个SQL执行报错,那APP报错,我们会去查找它的原因。

但如果它是一个错误的SQL,却被执行成功了,返回APP执行成功,那我们就感知不到它。而它一定会导致更新成一个完全错误的值,使我们的数据产生极大的破坏。

幸好这次只是在jira只执行了一次,但如果这样的SQL上线后被APP反复执行,将会给我们的线上数据产生不可估量的破坏。


因此必须避免在update的列更新中使用and。切记。

<think>嗯,用户让我在SudentInfo数据库中用DML进行一系列查询操作。首先,我需要确认一下数据库的结构,可能涉及的表有学生表(Student)、课程表(Course)、选课表(SC)吧。每个问题对应的表结构可能不同,所以得先理清楚各个表的字段。 第一个问题是查询学生的学号、姓名、性别、出生日期和所在系。这应该直接从Student表中选择这些字段,简单。不过要注意用户可能将系别字段命名成department或者dept之类的,需要确认字段名是否正确。 第二个问题要显示选课情况,成绩加5,并为列设置中文别名。这里需要用到SC表,选择学号、课程号,成绩加5,然后用AS关键字给列起中文别名。需要注意的是,如果成绩是整数类型,加5没问题,但如果有约束比如超过100可能会出问题,不过用户可能只是暂时展示,不影响原数据。 第三个问题要去重显示选课学生的学号,用DISTINCT关键字就行,简单。 第四个问题查询成绩在80到90之间的学生,可以用BETWEEN或者>=和<=组合,不过要注意是否包含边界值,用户的需求应该包括80和90,所以BETWEEN是合适的。 第五个问题查找姓名以S开头的学生,这里要注意数据库是否区分大小写,通常可能用LIKE 'S%',但如果数据库不区分,可能也会匹配小写s,不过用户示例中用了S开头,应该按大写处理。 第六个查询有考试成绩的学生,即成绩不为空,用IS NOT NULL来判断,但成绩字段如果是数值型,可能默认不为空,但题目特别说明,所以需要加上条件。 第七个问题,计算机系且年龄大于18岁。年龄可能需要通过出生日期计算,比如用YEAR(NOW()) - YEAR(BirthDate)来得到年龄,或者用DATEDIFF函数。另外,所在系是计算机系,可能字段名是department,值可能是'计算机系'或者其他类似名称,需保持一致。 第八个问题比较复杂,需要统计选修超过2门的学生,按平均成绩排序。这需要用到GROUP BY学号,HAVING COUNT(*) >2,然后计算平均成绩,并按平均成绩降序排列。注意平均成绩可能需要保留小数,用AVG函数即可。 第九个问题连接查询,学生表和选课表以及课程表,通过学号连接Student和SC,再通过课程号连接SC和Course,选出学号、姓名、课程名和成绩。 第十个问题,可以用连接查询或者嵌套查询。连接三个表,筛选课程名为English且成绩大于80的学生学号。或者子查询先找到课程号,再在SC中匹配成绩和学号。 另外,用户可能存在的误区是表之间的连接条件是否正确,比如是否有多对多关系,或者是否有正确的JOIN条件。同时,需要注意字段别名是否准确,尤其是中文别名需要用引号或者方括号,根据数据库类型而定,比如在SQL Server中使用AS [成绩],在MySQL中用反引号。 还有,用户提到的DML操作,虽然SELECT通常属于DQL,但有时候也被归为DML的一部分,可能需要确认,但一般按标准回答即可。最后,确保每个查询的语法正确,比如逗号分隔字段,条件语句的正确顺序等。</think>以下是针对SudentInfo数据库的DML查询实现,按题目要求分步说明: --- ### **1. 查询全体学生基本信息** ```sql SELECT 学号, 姓名, 性别, 出生日期, 所在系 FROM Student; ``` **说明**:直接选择目标列,需确保表中存在对应字段 --- ### **2. 显示选课情况(成绩+5,中文别名)** ```sql SELECT 学号 AS 学生编号, 课程号 AS 课程编号, (成绩 + 5) AS 调整后成绩 FROM SC; ``` **说明**:`AS`关键字定义中文列别名,注意成绩字段应为数值型 --- ### **3. 显示不重复的选课学号** ```sql SELECT DISTINCT 学号 FROM SC; ``` **说明**:`DISTINCT`关键字消除重复行 --- ### **4. 查询80~90分成绩记录** ```sql SELECT 学号, 课程号, 成绩 FROM SC WHERE 成绩 BETWEEN 80 AND 90; ``` **替代写法**: ```sql WHERE 成绩 >= 80 AND 成绩 <= 90; ``` --- ### **5. 查询姓名以S开头的学生** ```sql SELECT 学号, 姓名 FROM Student WHERE 姓名 LIKE 'S%'; ``` **注意**:`LIKE`区分大小写,如需不区分可用`ILIKE` --- ### **6. 查询有考试成绩的记录** ```sql SELECT 学号, 课程号 FROM SC WHERE 成绩 IS NOT NULL; ``` --- ### **7. 计算机系18岁以上学生** ```sql SELECT 学号, 姓名 FROM Student WHERE 所在系 = '计算机系' AND DATEDIFF(YEAR, 出生日期, GETDATE()) > 18; ``` **说明**:使用`DATEDIFF`函数计算年龄,不同数据库时间函数可能不同 --- ### **8. 统计选修超过2门的学生** ```sql SELECT 学号, AVG(成绩) AS 平均成绩, COUNT(*) AS 选课门数 FROM SC GROUP BY 学号 HAVING COUNT(*) > 2 ORDER BY 平均成绩 DESC; ``` --- ### **9. 学生选课详细信息(连接查询)** ```sql SELECT s.学号, s.姓名, c.课程名, sc.成绩 FROM Student s JOIN SC sc ON s.学号 = sc.学号 JOIN Course c ON sc.课程号 = c.课程号; ``` --- ### **10. 查询English课程高分学生** **嵌套查询写法**: ```sql SELECT 学号 FROM SC WHERE 课程号 IN ( SELECT 课程号 FROM Course WHERE 课程名 = 'English' ) AND 成绩 > 80; ``` **连接查询写法**: ```sql SELECT sc.学号 FROM SC sc JOIN Course c ON sc.课程号 = c.课程号 WHERE c.课程名 = 'English' AND sc.成绩 > 80; ``` --- ### **注意事项** 1. 实际字段名需与数据库表结构一致 2. 中文别名建议使用`AS`关键字显式声明 3. 日期计算函数根据数据库类型调整(如MySQL用`YEAR(NOW()) - YEAR(出生日期)`) 4. 性能优化建议:对常用查询字段建立索引 需要具体字段调整或执行计划分析,可提供数据库表结构进一步优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值