数据库刷题记录

在这里插入图片描述

SELECT 
    COUNT(*) AS male_num,
    ROUND (AVG(gpa),1) AS avg_gpa
FROM user_profile
WHERE gender = 'male';

COUNT(*)是一个整体,
COUNT 与 (*)之间不要加空格
因为有些OJ平台会将COUNT (*)判为格式错误
要求使用标准COUNT(*)写法

SELECT device_id, gender, age, university
FROM user_profile
WHERE age != NULL;  -- 这也是错误的写法!

为什么仍然错误?

  1. NULL 的特殊性:在 SQL 中,任何与 NULL 的比较运算(包括 =!=>< 等)都会返回 UNKNOWN,而不是 TRUE 或 FALSE
  2. WHERE 子句:只会返回条件判断为 TRUE 的行,而 UNKNOWN 会被当作 FALSE 处理

正确写法:

必须使用专门的 IS NOT NULL 操作符:

-- 正确写法 ✅
SELECT device_id, gender, age, university
FROM user_profile
WHERE age IS NOT NULL;

对比实验:

假设数据:

| device_id | age |
|-----------|-----|
| 10001     | 20  |
| 10002     | NULL|

你的错误写法:

SELECT * FROM user_profile WHERE age != NULL;
-- 返回:空结果(不会返回 10001)

正确写法:

SELECT * FROM user_profile WHERE age IS NOT NULL;
-- 返回:10001 | 20

记忆技巧:

把 NULL 想象成一个"黑洞":

  • 任何与 NULL 的常规比较都会被"吞噬"(变成 UNKNOWN)
  • 必须用专门的"手电筒"(IS NULL/IS NOT NULL)才能检测它

进阶知识:

如果确实需要与其他值一起比较 NULL,可以:

-- 查询 age 不是 20 的记录(包括 NULL)
SELECT * FROM user_profile WHERE age != 20 OR age IS NULL;

-- MySQL 专用简写(非标准语法):
SELECT * FROM user_profile WHERE age <=> NULL;  -- 等价于 IS NULL

通俗易懂讲解 SQL 中的 INNOT IN

1. IN 操作符:相当于"属于"

比喻:

就像老师问:“哪些同学是来自北京、上海或广州的?” —— 这就是 IN 的用法

作用:

检查某个值是否在一组给定的值中

基本语法:

SELECT 列名 FROM 表名 
WHERE 列名 IN (1,2,3,...);

实际例子:

-- 查询来自北京大学、清华大学或复旦大学的学生
SELECT device_id, university
FROM user_profile
WHERE university IN ('北京大学', '清华大学', '复旦大学');

等价写法:

-- 上面的IN查询等价于多个OR条件
SELECT device_id, university
FROM user_profile
WHERE university = '北京大学' 
   OR university = '清华大学'
   OR university = '复旦大学';

特点:

  • 比多个 OR 条件更简洁
  • 可以包含很多值(几十上百个都行)
  • 执行效率通常比多个 OR 更高

2. NOT IN 操作符:相当于"不属于"

比喻:

就像老师说:“除了迟到的小明、小红,其他同学都可以参加活动” —— 这就是 NOT IN 的用法

作用:

检查某个值是否在一组给定的值中

基本语法:

SELECT 列名 FROM 表名 
WHERE 列名 NOT IN (1,2,3,...);

实际例子:

-- 查询不是来自北京、上海或广州的学生
SELECT device_id, university
FROM user_profile
WHERE university NOT IN ('北京大学', '清华大学', '复旦大学');

等价写法:

-- 上面的NOT IN查询等价于多个AND条件
SELECT device_id, university
FROM user_profile
WHERE university != '北京大学' 
  AND university != '清华大学'
  AND university != '复旦大学';

3. 重要注意事项

NULL 值问题:

-- 如果NOT IN列表中有NULL值,整个查询会返回空结果!
SELECT * FROM table WHERE col NOT IN (1, 2, NULL); -- 错误示范

-- 正确做法:先处理NULL值
SELECT * FROM table 
WHERE col NOT IN (1, 2) AND col IS NOT NULL;

性能建议:

  • 当列表值很多时(如超过100个),考虑改用临时表或JOIN
  • 对大型表,确保相关列有索引

4. 实际应用场景

IN 的典型用途:

  • 查找特定类别的商品
  • 筛选来自某些地区的用户
  • 选择特定状态(如"已支付"、“已发货”)的订单

NOT IN 的典型用途:

  • 排除黑名单用户
  • 查找未完成的订单
  • 筛选不在某些部门的员工

5. 扩展用法

子查询中使用:

-- 查找有订单的用户
SELECT * FROM customers
WHERE id IN (SELECT customer_id FROM orders);

-- 查找没有订单的用户
SELECT * FROM customers
WHERE id NOT IN (SELECT customer_id FROM orders);

与其他条件组合:

-- 25岁以上且来自特定学校的学生
SELECT * FROM user_profile
WHERE age > 25 
  AND university IN ('北京大学', '清华大学');

记住:IN 是"属于这些",NOT IN 是"不属于这些",就像集合的"包含"和"不包含"关系!

你的 SQL 查询语句中的括号使用是 正确且必要的,但最后的 DESC 放错位置了。以下是修正和建议:

修正后的查询:

SELECT device_id, gender, age, university, gpa
FROM user_profile
WHERE (gpa > 3.5 AND university = '山东大学') 
   OR (gpa > 3.8 AND university = '复旦大学')
ORDER BY gpa DESC;  -- DESC 应该放在 ORDER BY 子句中

关于括号的说明:

  1. 你的括号逻辑完全正确

    • 清晰划分了两种条件组合:
      (条件A AND 条件B) OR (条件C AND 条件D)
      
    • 不加括号会改变运算优先级(AND 优先级高于 OR)
  2. 等价的无括号写法(不推荐,可读性差):

    WHERE gpa > 3.5 AND university = '山东大学' 
       OR gpa > 3.8 AND university = '复旦大学'
    

常见改进建议:

  1. 添加缩进提升可读性

    SELECT device_id, gender, age, university, gpa
    FROM user_profile
    WHERE (gpa > 3.5 AND university = '山东大学') 
       OR (gpa > 3.8 AND university = '复旦大学')
    ORDER BY gpa DESC;
    
  2. 如果条件更复杂,可以用注释说明

    WHERE 
        /* 山东大学学生且GPA>3.5 */
        (gpa > 3.5 AND university = '山东大学') 
        OR 
        /* 复旦大学学生且GPA>3.8 */
        (gpa > 3.8 AND university = '复旦大学')
    
  3. 其他等效写法(使用 IN + CASE WHEN):

    WHERE university IN ('山东大学', '复旦大学')
      AND gpa > CASE 
                  WHEN university = '山东大学' THEN 3.5
                  WHEN university = '复旦大学' THEN 3.8
                END
    

为什么你的原查询报错?

  • DESC 是排序方向关键字,必须配合 ORDER BY 使用
  • 错误写法:WHERE ... DESC
  • 正确写法:ORDER BY column_name DESC

你的 SQL 查询语句是:

SELECT device_id, age, university
FROM user_profile
WHERE university LIKE '北京%';

查询解析:

  1. 功能:查询大学名称以"北京"开头的用户的设备ID、年龄和大学信息
  2. 关键点
    • LIKE '北京%'%是通配符,表示匹配"北京"开头的任意字符串
    • 例如会匹配:“北京大学”、"北京理工大学"等

预期结果:

假设数据:

+-----------+-----+--------------+
| device_id | age | university   |
+-----------+-----+--------------+
| 10001     | 20  | 北京大学     |
| 10002     | 21  | 清华大学     |
| 10003     | 22  | 北京理工大学 |
| 10004     | 23  | 复旦大学     |
+-----------+-----+--------------+

查询结果:

+-----------+-----+--------------+
| device_id | age | university   |
+-----------+-----+--------------+
| 10001     | 20  | 北京大学     |
| 10003     | 22  | 北京理工大学 |
+-----------+-----+--------------+

其他常用通配符:

  1. _:匹配单个字符

    -- 匹配"北京"开头且只有4个字的大学(如:北京大学)
    WHERE university LIKE '北京__'
    
  2. %:匹配任意长度字符(包括0个)

    -- 匹配包含"北京"的大学(如:北京大学、中国北京学院)
    WHERE university LIKE '%北京%'
    
  3. 组合使用:

    -- 匹配以"北京"开头,以"大学"结尾的学校
    WHERE university LIKE '北京%大学'
    

性能建议:

  1. LIKE '北京%' 可以使用索引(前缀匹配)
  2. LIKE '%北京%' 通常无法使用索引,大数据量时性能较差
  3. 如果经常需要这种查询,可以考虑全文索引
SELECT MAX(gpa) 
FROM user_profile;

查询解析:

  1. 功能:查找 user_profile 表中 gpa 字段的最大值
  2. 关键点
    • MAX() 是聚合函数,返回指定列的最大值
    • 会扫描所有行的 gpa 值(自动忽略 NULL 值)

预期结果:

假设数据:

+------+
| gpa  |
+------+
| 3.2  |
| 3.8  |
| 4.0  |
| NULL |
| 3.5  |
+------+

查询将返回:

+----------+
| MAX(gpa) |
+----------+
| 4.0      |
+----------+

SQL ROUND(MAX(gpa), 1) AS gpa 语法详解

这个表达式由三个关键部分组成,我将逐一详细解释:

1. MAX(gpa) - 聚合函数

  • 功能:从 gpa 列中找出最大值
  • 特点
    • 自动忽略 NULL 值
    • 如果所有值都是 NULL,返回 NULL
  • 示例
    -- 假设数据: 3.2, 3.8, 4.0, NULL
    SELECT MAX(gpa) FROM user_profile;
    -- 返回: 4.0
    

2. ROUND(数值, 小数位数) - 四舍五入函数

  • 参数
    • 第一个参数:要舍入的数值(这里是 MAX(gpa) 的结果)
    • 第二个参数:保留的小数位数(这里是 1)
  • 舍入规则
    • 标准四舍五入
    • 如果恰好是中间值(如 3.25 保留1位),不同数据库可能处理不同
  • 示例
    SELECT ROUND(3.14159, 1);  -- 返回 3.1
    SELECT ROUND(3.85, 1);     -- 返回 3.9
    

3. AS gpa - 列别名

  • 作用:为计算结果列指定显示名称
  • 特点
    • AS 关键字可省略(SELECT MAX(gpa) gpa
    • 当列名包含空格或特殊字符时必须用引号:
      SELECT MAX(gpa) AS '最高 GPA' FROM user_profile;
      

完整执行流程

  1. 先执行 MAX(gpa) 找出最大值(如 3.82)
  2. 然后执行 ROUND(3.82, 1) 得到 3.8
  3. 最后将结果列命名为 gpa

常见变体

  1. 不同数据库的差异

    -- MySQL/PostgreSQL
    SELECT ROUND(MAX(gpa), 1) AS gpa;
    
    -- SQL Server
    SELECT ROUND(MAX(gpa), 1, 1) AS gpa; -- 第三个参数控制舍入方式
    
  2. 其他舍入方式

    -- 向上取整
    SELECT CEILING(MAX(gpa)) AS gpa;
    
    -- 向下取整
    SELECT FLOOR(MAX(gpa)) AS gpa;
    
    -- 截断小数位
    SELECT TRUNCATE(MAX(gpa), 1) AS gpa; -- MySQL
    
  3. 格式化输出

    -- 返回字符串类型
    SELECT FORMAT(MAX(gpa), 1) AS gpa; -- MySQL
    

要查询复旦大学学生的最高 GPA 并保留到小数点后1位,可以使用以下 SQL 查询:

SELECT ROUND(MAX(gpa), 1) AS gpa
FROM user_profile
WHERE university = '复旦大学';

查询解析:

  1. WHERE university = '复旦大学' - 筛选复旦大学的学生记录
  2. MAX(gpa) - 计算这些学生的最大 GPA 值
  3. ROUND(..., 1) - 将结果四舍五入到小数点后1位
  4. AS gpa - 将结果列命名为 gpa(与题目要求的输出一致)

预期结果:

+------+
| gpa  |
+------+
| 3.8  |
+------+
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值