news 2026/11/6 3:47:03

Linux、Shell、MySQL 测试卷逐题细讲(下篇:MySQL)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux、Shell、MySQL 测试卷逐题细讲(下篇:MySQL)

三、MySQL

1. 填空题

(1)计算行数并忽略 NULL 的函数

题目:使用 ______ 函数可以计算查询结果的行数,并忽略 NULL 值。

答案:COUNT()

展开讲:

SELECT COUNT(commission_pct) FROM employees;

COUNT(列名)只统计该列非 NULL 的行。

SELECT COUNT(*) FROM employees;

COUNT(*)统计所有行,不忽略 NULL。

区别:

  • COUNT(*):行数。
  • COUNT(列):该列非 NULL 的个数。
  • COUNT(DISTINCT 列):该列不重复非 NULL 值的个数。

题目说“忽略 NULL”,所以是COUNT(列名)。

易错点:

  • COUNT(1)和COUNT(*)在 MySQL 里基本等价,都统计行数。
  • COUNT(NULL)永远是 0,因为 NULL 不算值。

(2)分组后过滤

题目:使用 ______ 子句可以在分组后对结果进行过滤。

答案:HAVING

展开讲:

SELECT department_id, AVG(salary) FROM employees GROUP BY department_id HAVING AVG(salary) > 5000;

执行顺序大致:

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY
  • WHERE在分组前过滤行。
  • HAVING在分组后过滤组。

易错点:

  • WHERE里不能用聚合函数,比如WHERE AVG(salary) > 5000是错的。
  • HAVING可以用聚合函数,也可以用分组列。
  • 能写在WHERE里的条件尽量写WHERE,提前过滤效率更高。

(3)去重

题目:在 SELECT 语句中使用 ______ 可以确保查询返回的结果不包含重复的行。

答案:DISTINCT

展开讲:

SELECT DISTINCT department_id FROM employees;

DISTINCT作用于整个 SELECT 列表,不是只作用于某一列。

SELECT DISTINCT department_id, job_id FROM employees;

是“部门 + 职位”组合去重。

注意:

DISTINCT可能影响性能,因为要排序或哈希去重。

易错点:

  • SELECT DISTINCT a, b不是只对a去重,是对(a, b)组合去重。
  • DISTINCT和GROUP BY在只去重时效果类似,但语义不同。

(4)从一个表选数据插入另一个表

题目:使用 ______ 语句可以从一个表中选择数据并插入到另一个表中。

答案:INSERT INTO ... SELECT

展开讲:

INSERT INTO emp_backup(employee_id, first_name) SELECT employee_id, first_name FROM employees;
  • 列要对应。
  • 可以加WHERE过滤。
INSERT INTO emp_backup(employee_id, first_name) SELECT employee_id, first_name FROM employees WHERE department_id = 10;

注意:

  • 目标表要存在。
  • 自增列、默认值要处理好。
  • 列顺序要对应,不写列名时按表结构顺序。

(5)DELETE 中的条件子句

题目:使用 ______ 子句可以在 DELETE 语句中删除符合特定条件的行。

答案:WHERE

展开讲:

DELETE FROM employees WHERE employee_id = 100;

不加WHERE会删全表:

DELETE FROM employees;

注意:

  • DELETE可以回滚(在事务里)。
  • TRUNCATE TABLE更快,但不能带WHERE,一般也不能回滚。
  • 生产环境删数据前先SELECT确认条件。

(6)创建表时定义主键

题目:使用 ______ 子句可以在创建表时定义主键约束。

答案:PRIMARY KEY

展开讲:

列级写法:

CREATE TABLE t ( id INT PRIMARY KEY, name VARCHAR(20) );

表级写法:

CREATE TABLE t ( id INT, name VARCHAR(20), PRIMARY KEY (id) );

特点:

  • 主键唯一。
  • 主键不能为 NULL。
  • 一个表只能有一个主键。

易错点:

  • 主键和唯一索引不是一回事,主键不能 NULL,唯一索引可以。
  • 复合主键要用表级写法。

(7)事务中临时保存但不提交

题目:使用 ______ 语句可以将当前事务的更改临时保存,但不提交。

答案:SAVEPOINT

展开讲:

SAVEPOINT sp1;

回滚到保存点:

ROLLBACK TO SAVEPOINT sp1;

严格说,SAVEPOINT是设置保存点,不是“保存更改”。事务里的更改在COMMIT前都还没真正提交。按试卷常见答案写SAVEPOINT。

补充:

  • COMMIT:提交事务。
  • ROLLBACK:回滚整个事务。
  • ROLLBACK TO SAVEPOINT sp1:只回滚到保存点。

(8)设置事务隔离级别

题目:使用 ______ 语句可以设置事务的隔离级别。

答案:SET TRANSACTION ISOLATION LEVEL

展开讲:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

常见隔离级别:

  • READ UNCOMMITTED:读未提交,脏读可能。
  • READ COMMITTED:读已提交,避免脏读。
  • REPEATABLE READ:可重复读,MySQL 默认。
  • SERIALIZABLE:串行化,最严格。

注意:

SET TRANSACTION一般作用于下一个事务;全局设置用:

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

(9)创建表时设置默认值

题目:使用 ______ 子句可以在创建表时为某个列设置默认值。

答案:DEFAULT

展开讲:

CREATE TABLE t ( id INT, status INT DEFAULT 0 );

插入时不指定status,就是 0。

注意:

  • DEFAULT NULL是默认允许 NULL。
  • NOT NULL DEFAULT 0是常见组合。
  • MySQL 8 支持表达式默认值,但一般列默认值用字面量。

(10)删除表上的索引

题目:使用 ______ 语句可以删除表上的一个索引。

答案:DROP INDEX

展开讲:

DROP INDEX idx_name ON table_name;

也可以:

ALTER TABLE table_name DROP INDEX idx_name;

注意:

  • 主键索引用DROP PRIMARY KEY。
  • 删除索引前确认没有查询依赖它。
  • 删除索引可能影响查询性能,但能减少写入开销。

2. 选择题

(1)创建存储过程

题目:

a) CREATE PROCEDURE proc_name() BEGIN ... END b) CREATE FUNCTION proc_name() RETURNS ... BEGIN ... END c) CREATE TRIGGER proc_name() AFTER ... BEGIN ... END

答案:a

展开讲:

存储过程:

CREATE PROCEDURE proc_name() BEGIN -- SQL 语句 END;

函数:

CREATE FUNCTION func_name() RETURNS INT BEGIN RETURN 1; END;

触发器:

CREATE TRIGGER trig_name AFTER INSERT ON t FOR EACH ROW BEGIN -- ... END;

三者区别:

  • 存储过程:用CALL调用,可以有输出参数。
  • 函数:在 SQL 里使用,必须返回一个值。
  • 触发器:在 INSERT/UPDATE/DELETE 时自动执行。

易错点:

  • 存储过程名后面要带括号()。
  • 函数必须写RETURNS类型。

(2)全文搜索索引类型

题目:

a) BTREE b) HASH c) FULLTEXT d) SPATIAL

答案:c

展开讲:

  • BTREE:最常用,范围查询、排序。
  • HASH:等值查询快,不支持范围。
  • FULLTEXT:全文搜索,适合文本关键词。
  • SPATIAL:空间数据,地理坐标。

全文索引示例:

CREATE FULLTEXT INDEX idx_content ON articles(content);

查询:

SELECT * FROM articles WHERE MATCH(content) AGAINST('Linux');

注意:

  • InnoDB 从 MySQL 5.6 开始支持 FULLTEXT。
  • 中文全文搜索需要分词插件,默认对中文支持有限。

(3)ACID 的 A

题目:

a) Atomicity b) Authenticity c) Authorization d) Aggregation

答案:a

展开讲:

ACID:

  • Atomicity:原子性,要么全成功,要么全失败。
  • Consistency:一致性,事务前后数据满足约束。
  • Isolation:隔离性,并发事务互不干扰。
  • Durability:持久性,提交后不丢。

A 是 Atomicity。


(4)更改现有列的数据类型

题目:

a) MODIFY TABLE table_name column_name data_type b) ALTER TABLE table_name MODIFY column_name data_type c) CHANGE TABLE table_name column_name data_type d) UPDATE TABLE table_name column_name data_type

答案:b

展开讲:

ALTER TABLE table_name MODIFY column_name data_type;

MODIFY只改类型,不改列名。

CHANGE可以同时改列名和类型:

ALTER TABLE table_name CHANGE old_col new_col data_type;

注意:

  • ALTER TABLE是改表结构。
  • UPDATE是改数据。
  • 改类型时要注意数据兼容,比如字符串转数字可能失败。

(5)支持事务的存储引擎

题目:

a) MyISAM b) InnoDB c) MEMORY d) CSV

答案:b

展开讲:

  • InnoDB:支持事务、行锁、外键、崩溃恢复,MySQL 默认。
  • MyISAM:不支持事务,表锁,读多写少老场景。
  • MEMORY:内存表,重启丢数据。
  • CSV:以 CSV 文件存储,功能有限。

补充:

查看表的存储引擎:

SHOW TABLE STATUS LIKE 'employees';

(6)导入 SQL 脚本

题目:

a) mysqlimport -u user -p database < script.sql b) mysql -u user -p database < script.sql c) source -u user -p database script.sql d) mysqldump -u user -p database < script.sql

答案:b

展开讲:

mysql -u user -p database < script.sql
  • mysql客户端执行 SQL。
  • <把脚本作为标准输入。

其他:

  • mysqlimport:导入文本数据,不是 SQL 脚本。
  • source:MySQL 客户端内部命令,不是 shell 命令。
  • mysqldump:导出,不是导入。

登录后也可以:

SOURCE /path/script.sql;

易错点:

  • mysql后面跟数据库名,不是-D也行,但习惯写库名。
  • 脚本里如果有USE语句,也可以不指定库名。

(7)添加外键约束

题目:原卷选项显示乱:

1) ADD CONSTRAINT FOREIGN KEY (column_name) REFERENCES table_name(column_name) 2) ALTER TABLE table_name ADD FOREIGN KEY (column_name) REFERENCES other_table(column_name) 3) CREATE FOREIGN KEY (column_name) REFERENCES table_name(column_name) 4) INSERT FOREIGN KEY (column_name) REFERENCES table_name(column_name)

答案:2

展开讲:

ALTER TABLE table_name ADD FOREIGN KEY (column_name) REFERENCES other_table(column_name);

带约束名:

ALTER TABLE orders ADD CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(id);

注意:

  • 外键列和引用列类型要一致。
  • 存储引擎要 InnoDB。
  • 被引用列一般是主键或唯一键。
  • 外键会影响写入性能,互联网场景很多公司不用物理外键。

(8)优化表

题目:

a) OPTIMIZE TABLE table_name b) ANALYZE TABLE table_name c) CHECK TABLE table_name d) REPAIR TABLE table_name

答案:a

展开讲:

  • OPTIMIZE TABLE:整理表空间,回收碎片。
  • ANALYZE TABLE:更新统计信息,优化器用。
  • CHECK TABLE:检查表是否有错误。
  • REPAIR TABLE:修复表。

题目问“优化一个表”,选OPTIMIZE TABLE。

补充:

  • InnoDB 的OPTIMIZE TABLE实际是重建表,可能锁表,大表慎用。
  • ANALYZE TABLE在统计信息不准时也常用。

(9)查看数据库中的所有表

题目:

a) SHOW DATABASES b) SHOW TABLES c) SHOW COLUMNS d) SHOW INDEXES

答案:b

展开讲:

SHOW TABLES;

看当前数据库的表。

SHOW DATABASES;

看有哪些数据库。

SHOW COLUMNS FROM table_name;

看列。

SHOW INDEXES FROM table_name;

看索引。

易错点:

  • SHOW TABLES要先USE某个库,或者写SHOW TABLES FROM db_name。
  • SHOW DATABASES不是看表。

(10)创建新用户

题目:

a) CREATE USER 'username'@'host' IDENTIFIED BY 'password' b) ADD USER 'username'@'host' IDENTIFIED BY 'password' c) INSERT INTO mysql.user (...) VALUES (...) d) NEW USER 'username'@'host' IDENTIFIED BY 'password'

答案:a

展开讲:

CREATE USER 'username'@'host' IDENTIFIED BY 'password';

授权:

GRANT ALL PRIVILEGES ON db.* TO 'username'@'host'; FLUSH PRIVILEGES;

注意:

  • 'username'@'host'中 host 可以是localhost、%等。
  • 不推荐直接往mysql.user插数据。
  • MySQL 8 默认认证插件变了,老客户端可能连不上,需要IDENTIFIED WITH mysql_native_password BY 'password'。

3. SQL 分析题

表结构里department_name原卷 OCR 粘连成department_na,下面按department_name写。四张表关系:

employees.department_id -> departments.department_id employees.job_id -> jobs.job_id departments.location_id -> locations.location_id employees.manager_id -> employees.employee_id(自连接)

(1)员工姓名、邮箱、职位名称、部门名称

题目:查询每个员工的姓名、邮箱、职位名称以及所在部门名称。

答案:

-- 员工表关联职位表和部门表 SELECT e.first_name, e.last_name, e.email, j.job_title, d.department_name FROM employees e JOIN jobs j ON e.job_id = j.job_id JOIN departments d ON e.department_id = d.department_id;

展开讲:

  • employees别名e。
  • jobs别名j,通过job_id关联。
  • departments别名d,通过department_id关联。

用JOIN默认是INNER JOIN,只返回能关联上的行。如果员工没有部门,就不会出现。题目说“每个员工”,严格说可以用LEFT JOIN保留没有部门的员工:

FROM employees e LEFT JOIN jobs j ON e.job_id = j.job_id LEFT JOIN departments d ON e.department_id = d.department_id;

但考试一般写内连接即可。

易错点:

  • 多表连接时字段名要加表别名,避免歧义。
  • first_name和last_name是两列,题目说“姓名”要都查出来。

(2)月薪最高的员工

题目:查询月薪最高的员工的姓名、职位名称以及月薪。

答案:

-- 先子查询找出最高月薪,再拿这个值去筛员工 SELECT e.first_name, e.last_name, j.job_title, e.salary FROM employees e JOIN jobs j ON e.job_id = j.job_id WHERE e.salary = (SELECT MAX(salary) FROM employees);

展开讲:

子查询(SELECT MAX(salary) FROM employees)返回一个值,外层用=比较。

如果有多个人并列最高,这条会全部返回。

另一种写法:

SELECT e.first_name, e.last_name, j.job_title, e.salary FROM employees e JOIN jobs j ON e.job_id = j.job_id ORDER BY e.salary DESC LIMIT 1;

这种只返回一个,并列时可能漏人。子查询写法更稳。

易错点:

  • 子查询返回多行时不能用=,要用IN。
  • MAX忽略 NULL,如果全是 NULL 返回 NULL。

(3)每个部门的平均月薪

题目:查询每个部门的平均月薪。

答案:

-- 按部门分组求平均工资 SELECT d.department_name, AVG(e.salary) AS avg_salary FROM departments d LEFT JOIN employees e ON d.department_id = e.department_id GROUP BY d.department_id, d.department_name;

展开讲:

  • LEFT JOIN保留没有员工的部门,平均值为 NULL。
  • GROUP BY按部门分组。
  • AVG(e.salary)自动忽略 NULL。

GROUP BY里带上d.department_name是为了兼容ONLY_FULL_GROUP_BY模式。

易错点:

  • GROUP BY只写department_id在某些模式下会报错,因为department_name不在聚合函数里。
  • 想保留没员工的部门用LEFT JOIN,只看有员工的部门用JOIN。

(4)月薪高于 5000 的员工

题目:查询部门中员工月薪高于 5000 的所有员工的姓名、月薪以及所在部门名称。

答案:

-- 直接 where 过滤 salary SELECT e.first_name, e.last_name, e.salary, d.department_name FROM employees e JOIN departments d ON e.department_id = d.department_id WHERE e.salary > 5000;

展开讲:

题目里“部门中”只是描述,不是要求按部门分组,直接过滤工资即可。

如果要用LEFT JOIN保留没部门的员工,把JOIN换成LEFT JOIN。

易错点:

  • WHERE在GROUP BY之前执行,这里不需要分组。
  • 工资是double,比较时注意精度,一般没问题。

(5)奖金率最高的员工

题目:查询奖金率最高的员工的姓名、职位名称以及奖金率。

答案:

-- 奖金率最高,注意 commission_pct 可能为 NULL SELECT e.first_name, e.last_name, j.job_title, e.commission_pct FROM employees e JOIN jobs j ON e.job_id = j.job_id WHERE e.commission_pct = (SELECT MAX(commission_pct) FROM employees);

展开讲:

MAX(commission_pct)会忽略 NULL。

如果所有人都没有奖金率,子查询返回 NULL,= NULL不成立,结果为空。要处理可以用IS NULL判断,但题目一般不考虑。

易错点:

  • commission_pct是奖金率,不是奖金金额。
  • NULL 参与比较要用IS NULL,不能用=。

(6)每个职位的最高和最低月薪

题目:查询每个职位的最高月薪和最低月薪。

答案:

-- 按职位分组,取 max 和 min SELECT j.job_title, MAX(e.salary) AS max_salary, MIN(e.salary) AS min_salary FROM jobs j LEFT JOIN employees e ON j.job_id = e.job_id GROUP BY j.job_id, j.job_title;

展开讲:

用jobs左连接employees,没有员工的职位也会出现,MAX/MIN为 NULL。

如果只关心有员工的职位,用JOIN即可。

易错点:

  • MAX和MIN是聚合函数,必须配合GROUP BY。
  • 没员工的职位MAX/MIN是 NULL,不是 0。

(7)入职早于 2000 年

题目:查询入职时间早于 2000 年的所有员工的姓名、入职日期以及职位名称。

答案:

-- hiredate 是 datetime,直接和 '2000-01-01' 比较 SELECT e.first_name, e.last_name, e.hiredate, j.job_title FROM employees e JOIN jobs j ON e.job_id = j.job_id WHERE e.hiredate < '2000-01-01';

展开讲:

hiredate < '2000-01-01'表示 2000 年之前。

如果包含 2000 年当年,用:

WHERE e.hiredate < '2001-01-01'

或者:

WHERE YEAR(e.hiredate) < 2000

但YEAR()会导致索引失效,数据量大时少用。

易错点:

  • hiredate是datetime,字符串比较会隐式转换。
  • BETWEEN包含边界,注意是否需要包含 2000-01-01。

(8)每个部门员工人数

题目:查询每个部门的员工人数。

答案:

-- count(e.employee_id) 只统计有员工的行 SELECT d.department_name, COUNT(e.employee_id) AS emp_count FROM departments d LEFT JOIN employees e ON d.department_id = e.department_id GROUP BY d.department_id, d.department_name;

展开讲:

COUNT(e.employee_id)只统计非 NULL,没员工的部门得到 0。

如果用COUNT(*),左连接后没员工的部门也会有一行 NULL,会被算成 1,这是常见坑。

易错点:

  • COUNT(*)和COUNT(列)在左连接时结果可能不同。
  • 统计人数用COUNT(e.employee_id)更稳。

(9)每个部门月薪最高的员工

题目:查询在每个部门中月薪最高的员工的姓名、月薪以及部门名称。

答案:

-- 用部门 + 最高工资作为条件,找出每个部门工资最高的员工 SELECT e.first_name, e.last_name, e.salary, d.department_name FROM employees e JOIN departments d ON e.department_id = d.department_id WHERE (e.department_id, e.salary) IN ( SELECT department_id, MAX(salary) FROM employees GROUP BY department_id );

展开讲:

子查询按部门求最高工资,外层用(department_id, salary)元组匹配。

并列最高会全部返回。

MySQL 8 窗口函数写法:

SELECT first_name, last_name, salary, department_name FROM ( SELECT e.first_name, e.last_name, e.salary, d.department_name, ROW_NUMBER() OVER (PARTITION BY e.department_id ORDER BY e.salary DESC) AS rn FROM employees e JOIN departments d ON e.department_id = d.department_id ) t WHERE rn = 1;

考试写元组子查询即可。

易错点:

  • 元组IN要求两边字段顺序一致。
  • 如果部门有多个最高工资并列,元组写法会全部返回;ROW_NUMBER只返回一个,要用RANK才能并列。

(10)月薪超过部门平均月薪

题目:查询月薪超过部门平均月薪的员工的姓名、月薪以及所在部门名称。

答案:

-- 相关子查询:每个员工拿自己部门平均工资比较 SELECT e.first_name, e.last_name, e.salary, d.department_name FROM employees e JOIN departments d ON e.department_id = d.department_id WHERE e.salary > ( SELECT AVG(e2.salary) FROM employees e2 WHERE e2.department_id = e.department_id );

展开讲:

这是相关子查询:内层e2.department_id = e.department_id引用了外层当前行的部门。

每个员工都会执行一次子查询,算自己部门的平均工资。

注意:

  • 别名要区分,内层用e2。
  • 部门平均工资可能为 NULL,比较不成立。

易错点:

  • 相关子查询性能一般,数据量大时可以用派生表 join 优化。
  • 子查询里不能直接用外层别名以外的同名列,要加表别名。

(11)每个职位员工人数

题目:查询每个职位的员工人数。

答案:

-- 按职位分组统计人数 SELECT j.job_title, COUNT(e.employee_id) AS emp_count FROM jobs j LEFT JOIN employees e ON j.job_id = e.job_id GROUP BY j.job_id, j.job_title;

展开讲:

和部门人数类似,用jobs左连接,没人的职位显示 0。

易错点:

  • 职位表是jobs,员工表通过job_id关联。
  • COUNT(e.employee_id)不会把没人的职位算成 1。

(12)每个部门最高和最低月薪

题目:查询每个部门的最高月薪和最低月薪。

答案:

-- 部门分组后取 max/min SELECT d.department_name, MAX(e.salary) AS max_salary, MIN(e.salary) AS min_salary FROM departments d LEFT JOIN employees e ON d.department_id = e.department_id GROUP BY d.department_id, d.department_name;

展开讲:

MAX/MIN忽略 NULL,没员工的部门为 NULL。

易错点:

  • 和第(6)题结构一样,只是分组字段从职位换成部门。
  • GROUP BY要带上department_name避免ONLY_FULL_GROUP_BY报错。

(13)员工及其上级领导姓名

题目:查询每个员工的姓名、邮箱、职位名称以及他们的上级领导的姓名。

答案:

-- employees 表自连接,m 表示 manager SELECT e.first_name, e.last_name, e.email, j.job_title, m.first_name AS manager_first_name, m.last_name AS manager_last_name FROM employees e JOIN jobs j ON e.job_id = j.job_id LEFT JOIN employees m ON e.manager_id = m.employee_id;

展开讲:

  • e是员工。
  • m是领导,通过e.manager_id = m.employee_id关联。
  • 用LEFT JOIN保留没有领导的员工。

如果写JOIN,没有领导的员工(比如大老板)就查不出来。

易错点:

  • 自连接必须用不同别名。
  • manager_id可能为 NULL,必须用LEFT JOIN。

(14)每个部门平均奖金率

题目:查询每个部门的员工平均奖金率。

答案:

-- 奖金率是 commission_pct,按部门求平均 SELECT d.department_name, AVG(e.commission_pct) AS avg_commission FROM departments d LEFT JOIN employees e ON d.department_id = e.department_id GROUP BY d.department_id, d.department_name;

展开讲:

AVG忽略 NULL。如果部门里只有部分人有奖金率,平均的是有值的那些。

如果想把 NULL 当 0 算,用:

AVG(IFNULL(e.commission_pct, 0))

但题目一般按默认行为。

易错点:

  • AVG和COUNT一样忽略 NULL。
  • 奖金率是比例,不是金额,字段是commission_pct。

(15)每个城市员工人数

题目:查询每个城市的员工人数。

答案:

-- locations -> departments -> employees 三表关联 SELECT l.city, COUNT(e.employee_id) AS emp_count FROM locations l LEFT JOIN departments d ON l.location_id = d.location_id LEFT JOIN employees e ON d.department_id = e.department_id GROUP BY l.location_id, l.city;

展开讲:

关系链:

locations.location_id <- departments.location_id departments.department_id <- employees.department_id

用LEFT JOIN保留没有员工的城市,人数为 0。

易错点:

  • 三表连接顺序要从locations开始,再连departments,再连employees。
  • city可能重复,按location_id, city分组更准。

(16)每个部门职位种类数

题目:查询每个部门的职位种类数。

答案:

-- count(distinct job_id) 统计不重复的职位数 SELECT d.department_name, COUNT(DISTINCT e.job_id) AS job_kinds FROM departments d LEFT JOIN employees e ON d.department_id = e.department_id GROUP BY d.department_id, d.department_name;

展开讲:

COUNT(DISTINCT e.job_id)去重统计职位。

如果不用DISTINCT,统计的是员工人数,不是职位种类数。

易错点:

  • 一个部门有多个员工同一职位,只算一种。
  • COUNT(DISTINCT ...)忽略 NULL。

(17)工资高于其职位平均工资

题目:查询工资高于其职位平均工资的员工姓名、职位名称以及月薪。

答案:

-- 相关子查询:按员工自己的 job_id 算该职位平均工资 SELECT e.first_name, e.last_name, j.job_title, e.salary FROM employees e JOIN jobs j ON e.job_id = j.job_id WHERE e.salary > ( SELECT AVG(e2.salary) FROM employees e2 WHERE e2.job_id = e.job_id );

展开讲:

和第(10)题类似,只是内层按job_id分组,不是department_id。

内层e2.job_id = e.job_id引用外层当前员工的职位。

易错点:

  • 相关子查询每行执行一次,数据量大时慢。
  • 可以用JOIN派生表先算每个职位平均工资再比较,性能更好。

(18)每个国家员工人数

题目:查询每个国家的员工人数。

答案:

-- locations 里有 country_id,按国家统计 SELECT l.country_id, COUNT(e.employee_id) AS emp_count FROM locations l LEFT JOIN departments d ON l.location_id = d.location_id LEFT JOIN employees e ON d.department_id = e.department_id GROUP BY l.country_id;

展开讲:

locations表有country_id,按国家分组。

如果还有国家名称表,可以再关联,但试卷只给了四张表,所以显示country_id。

易错点:

  • country_id是国家编号,不是国家名。
  • 按国家统计要经过locations -> departments -> employees三表。

(19)没有领导的员工

题目:查询没有领导的员工的姓名以及职位名称。

答案:

-- manager_id 为 NULL 表示没有上级 SELECT e.first_name, e.last_name, j.job_title FROM employees e JOIN jobs j ON e.job_id = j.job_id WHERE e.manager_id IS NULL;

展开讲:

manager_id IS NULL判断没有上级。

不能用= NULL,SQL 里 NULL 比较要用IS NULL。

易错点:

  • manager_id = NULL永远不成立。
  • IS NULL和IS NOT NULL是专门判断 NULL 的。

(20)job_id 为 IT_PROG 的员工

题目:查询 job_id 为 "IT_PROG" 的员工的姓名、职位名称以及月薪。

答案:

-- 直接按 job_id 过滤 SELECT e.first_name, e.last_name, j.job_title, e.salary FROM employees e JOIN jobs j ON e.job_id = j.job_id WHERE e.job_id = 'IT_PROG';

展开讲:

job_id是字符串,要用单引号。

关联jobs表是为了拿job_title。

注意:

MySQL 默认排序规则可能不区分大小写,'it_prog'也能匹配;如果要求严格区分,用BINARY或改排序规则。

易错点:

  • job_id是varchar,不是数字,别写成WHERE job_id = IT_PROG。
  • 字符串比较可能受排序规则影响。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/6 3:45:27

157_求解失败不可行怎么查

这一章要解决什么 小林在期末前第 4 周给自己排晚自习。他给自己定的规矩只有两条&#xff1a;一周要坐满 20 小时&#xff1b;每晚不超过 2 小时&#xff0c;超过就睡不够。周一到周五能排&#xff0c;周末回家&#xff0c;所以一周只有 5 个晚上。两条规矩加"只有五天&q…

作者头像 李华
网站建设 2026/11/6 3:45:19

直播平台带宽成本降低 40% 实录:FFmpeg 转码链路与自适应码率实践

摘要:主导过一个流媒体直播平台的建设:接入海康威视等 10+ 品牌监控/教学硬件,日均直播时长超 2 万小时,万级并发观看。带宽是这类平台最大的成本项,我们通过转码参数优化 + 自适应码率 + 分辨率策略的组合拳,把带宽成本降低了约 40%。这篇文章讲完整链路:监控摄像头怎么…

作者头像 李华
网站建设 2026/11/6 3:44:50

SaaS 和私有化部署怎么选?数据、成本、安全一次说清

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/6 3:43:01

小程序基本绘图

完整全部代码1. app.json{"pages": ["pages/index/index"],"window": {"navigationBarTextStyle": "black","navigationStyle": "custom"},"style": "v2","renderer": &…

作者头像 李华
网站建设 2026/11/6 3:42:41

深度学习:强化学习基础与深度 Q 网络 DQN

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华