SQL练习题目

1. 组合两个表

题目描述:编写一个 SQL 查询,满足条件:无论 person 是否有地址信息,都需要基于上述两表提供 person 的以下信息:FirstName, LastName, City, State
表1: Person

±------------±--------+
| 列名 | 类型 |
±------------±--------+
| PersonId | int |
| FirstName | varchar |
| LastName | varchar |
±------------±--------+
PersonId 是上表主键
表2: Address

±------------±--------+
| 列名 | 类型 |
±------------±--------+
| AddressId | int |
| PersonId | int |
| City | varchar |
| State | varchar |
±------------±--------+
AddressId 是上表主键
解题思路:题目中要求无论person是否有地址信息,都要提供所要显示的信息,所以使用外部联结。外部联结可以包含没有关联行的行。

# Write your MySQL query statement below
SELECT FirstName, LastName, City, State
FROM Person LEFT OUTER JOIN Address
ON Person.PersonId = Address.PersonId;

2. 第二高的薪水

题目描述:编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) 。
±—±-------+
| Id | Salary |
±—±-------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
±—±-------+
例如上述 Employee 表,SQL查询应该返回 200 作为第二高的薪水。如果不存在第二高的薪水,那么查询应返回 null。
±--------------------+
| SecondHighestSalary |
±--------------------+
| 200 |
±--------------------+*
解题思路:LIMIT y OFFSET x表示跳过前x条数据,在接着读取y条。题中要求若不存在,返回null,可以使用IFNULL函数进行判断。

# Write your MySQL query statement below
SELECT
    IFNULL(
        (SELECT DISTINCT Salary 
        FROM Employee
        ORDER BY Salary DESC
        LIMIT 1 OFFSET 1),
        NULL)
AS SecondHighestSalary;

3. 超过经理收入的员工

题目描述:Employee 表包含所有员工,他们的经理也属于员工。每个员工都有一个 Id,此外还有一列对应员工的经理的 Id。

±—±------±-------±----------+
| Id | Name | Salary | ManagerId |
±—±------±-------±----------+
| 1 | Joe | 70000 | 3 |
| 2 | Henry | 80000 | 4 |
| 3 | Sam | 60000 | NULL |
| 4 | Max | 90000 | NULL |
±—±------±-------±----------+
给定 Employee 表,编写一个 SQL 查询,该查询可以获取收入超过他们经理的员工的姓名。在上面的表格中,Joe 是唯一一个收入超过他的经理的员工。

±---------+
| Employee |
±---------+
| Joe |
±---------+
解题思路:使用自联结

# Write your MySQL query statement below
SELECT a.Name AS Employee
FROM Employee AS a, Employee AS b
WHERE a.ManagerId = b.Id
    AND a.Salary > b.Salary

4. 查找重复的电子邮箱

题目描述:编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱。
示例:
±—±--------+
| Id | Email |
±—±--------+
| 1 | [email protected] |
| 2 | [email protected] |
| 3 | [email protected] |
±—±--------+
根据以上输入,你的查询应返回以下结果:
±--------+
| Email |
±--------+
| [email protected] |
±--------+
解法一:使用自联结

# Write your MySQL query statement below
SELECT DISTINCT a.Email
FROM Person AS a, Person AS b
WHERE a.Id != b.Id AND a.Email = b.Email

解法二:使用分组

# Write your MySQL query statement below
SELECT DISTINCT Email
FROM Person
GROUP BY Email
HAVING COUNT(Email) > 1;

5. 从不订购的客户

题目描述:某网站包含两个表,Customers 表和 Orders 表。编写一个 SQL 查询,找出所有从不订购任何东西的客户。
Customers 表:
±—±------+
| Id | Name |
±—±------+
| 1 | Joe |
| 2 | Henry |
| 3 | Sam |
| 4 | Max |
±—±------+
Orders 表:
±—±-----------+
| Id | CustomerId |
±—±-----------+
| 1 | 3 |
| 2 | 1 |
±—±-----------+
例如给定上述表格,你的查询应返回:
±----------+
| Customers |
±----------+
| Henry |
| Max |
±----------+
解题思路:只能采用IS NULL或IS NOT NULL,而不能采用=, <, <>, !=这些操作符来判断NULL。

# Write your MySQL query statement below
SELECT c.Name AS Customers
FROM Customers AS c LEFT OUTER JOIN Orders AS o 
ON o.CustomerId = c.Id
WHERE o.Id IS NULL;

6. 删除重复的电子邮箱

题目描述:编写一个 SQL 查询,来删除 Person 表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个。
±—±-----------------+
| Id | Email |
±—±-----------------+
| 1 | [email protected] |
| 2 | [email protected] |
| 3 | [email protected] |
±—±-----------------+
Id 是这个表的主键。
例如,在运行你的查询语句之后,上面的 Person 表应返回以下几行:
±—±-----------------+
| Id | Email |
±—±-----------------+
| 1 | [email protected] |
| 2 | [email protected] |
±—±-----------------+
解题思路:使用DELETE删除重复的行。要先将查询出的ID缓存起来,再根据此ID删除,因为mysql 不能先将select出表中的某些值,再这更新个表!通过对Email分组,然后取每一组的最小Id,便可以获得不重复元素的Id,其余Id均为重复Id。

# Write your MySQL query statement below
DELETE FROM Person
WHERE Id NOT IN (
    SELECT id
    FROM(
        SELECT MIN(Id) AS id
        FROM Person
        GROUP BY Email
    )t
);

7. 上升的温度

题目描述:给定一个 Weather 表,编写一个 SQL 查询,来查找与之前(昨天的)日期相比温度更高的所有日期的 Id。
±--------±-----------------±-----------------+
| Id(INT) | RecordDate(DATE) | Temperature(INT) |
±--------±-----------------±-----------------+
| 1 | 2015-01-01 | 10 |
| 2 | 2015-01-02 | 25 |
| 3 | 2015-01-03 | 20 |
| 4 | 2015-01-04 | 30 |
±--------±-----------------±-----------------+
例如,根据上述给定的 Weather 表格,返回如下 Id:
±—+
| Id |
±—+
| 2 |
| 4 |
±—+
解题思路:DATEDIFF求得两个日期的天数差。使用自然联结。

# Write your MySQL query statement below
SELECT b.Id
FROM Weather AS a, Weather AS b
WHERE b.Temperature > a.Temperature
    AND dateDiff(b.RecordDate,a.RecordDate) = 1 

使用子查询

# Write your MySQL query statement below
SELECT Id
FROM Weather AS a
WHERE Temperature > (
    SELECT Temperature
    FROM Weather
    WHERE dateDiff(a.RecordDate,Weather.RecordDate) = 1 
)

8. 从titles表获取按照title进行分组

题目描述:从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。注意对于重复的emp_no进行忽略(即emp_no重复的title不计算,title对应的数目t不增加)。

CREATE TABLE IF NOT EXISTS `titles` (
`emp_no` int(11) NOT NULL,
`title` varchar(50) NOT NULL,
`from_date` date NOT NULL,
`to_date` date DEFAULT NULL);

解题思路:使用分组。由于emp_no重复的title不计算,所以在COUNT函数中使用参数DINSICT,只对不同的值进行计数。

SELECT title, COUNT(DISTINCT emp_no) AS t
FROM titles
GROUP BY title
HAVING COUNT(*) >= 2

9. 联结三个表

题目描述:查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工

CREATE TABLE `departments` (
`dept_no` char(4) NOT NULL,
`dept_name` varchar(40) NOT NULL,
PRIMARY KEY (`dept_no`));
CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));

解题思路:三个表的联结。

SELECT e.last_name, e.first_name, dm.dept_name
FROM employees AS e
LEFT JOIN dept_emp AS de
ON e.emp_no = de.emp_no
LEFT JOIN departments AS dm
ON de.dept_no = dm.dept_no

10. 使用子查询

题目描述:你能使用子查询的方式找出属于Action分类的所有电影对应的title,description吗
film表包括:film_id 电影id;title 电影名称;description 电影描述信息
category表包括:category_id 电影分类id;name 电影分类名称;last_update 电影分类最后更新时间
film_category表包括:film_id 电影id;category_id 电影分类id;last_update 电影id和分类id对应关系的最后更新时间
解题思路:在category表中,由name确定category_id,再在film_category表中确定film_id,最后在film表中确定title和description。

SELECT title, description
FROM film
WHERE film_id IN (SELECT film_id
                  FROM film_category
                  WHERE category_id IN (
                                        SELECT category_id
                                        FROM category
                                        WHERE name = 'Action'))

题目二:查找排除最大、最小salary之后的当前(to_date = ‘9999-01-01’ )员工的平均工资avg_salary。

SELECT AVG(salary) AS avg_salary
FROM salaries
WHERE to_date = '9999-01-01'
    AND salary != (
            SELECT MAX(salary)
            FROM salaries
            WHERE to_date = '9999-01-01')
    AND salary != (
            SELECT MIN(salary)
            FROM salaries
            WHERE to_date = '9999-01-01')

11. 创建表

题目描述:创建一个actor表,包含如下列信息(注:sqlite获取系统默认时间是datetime(‘now’,‘localtime’))

CREATE TABLE actor
(
    actor_id    SMALLINT(5)    NOT NULL,
    first_name  VARCHAR(45)    NOT NULL,
    last_name   VARCHAR(45)    NOT NULL,
    last_update TIMESTAMP    NOT NULL DEFAULT (datetime('now','localtime')),
    PRIMARY KEY ('actor_id')
)

12. 插入数据

题目一:对于表actor批量插入如下数据,如果数据已经存在,请忽略。
insert or replace:如果不存在就插入,存在就更新
insert or ignore:如果不存在就插入,存在就忽略
只对UNIQUE约束的字段起作用。

INSERT OR IGNORE INTO actor(
    actor_id,
    first_name,
    last_name,
    last_update)
VALUES(
    '3',
    'ED',
    'CHASE',
    '2006-02-15 12:34:33')

题目二:请你创建一个actor_name表,并且将actor表中的所有first_name以及last_name导入该表。

CREATE TABLE actor_name(
    first_name VARCHAR(45) NOT NULL,
    last_name  VARCHAR(45) NOT NULL
);
INSERT INTO actor_name(
    first_name,
    last_name)
SELECT first_name, last_name
FROM actor;

13. 创建索引

题目描述:对first_name创建唯一索引uniq_idx_firstname,对last_name创建普通索引idx_lastname(请先创建唯一索引,再创建普通索引)
SQL插入索引语句有:
1普通索引:ALTER TABLE’table-name’ ADD INDEX index_name(‘column’)
2唯一索引:ALTER TABLE’table-name’ ADD UNIQUE(‘column’)
3主键索引:ALTER TABLE’table-name’ ADD PRIMARY KEY (‘column’)
(注:在 SQLite 中,除了重命名表和在已有的表中添加列,ALTER TABLE 命令不支持其他操作,所以使用CREATE)

CREATE UNIQUE INDEX uniq_idx_firstname ON actor(first_name);
CREATE INDEX idx_lastname ON actor(last_name);

题目二:使用索引进行查询。针对salaries表emp_no字段创建索引idx_emp_no,查询emp_no为10005。

SELECT *
FROM salaries
INDEXED BY idx_emp_no
WHERE emp_no = 10005

14. 增加列

ALTER TABLE actor
ADD create_date datetime NOT NULL DEFAULT '0000-00-00 00:00:00'

15. 更新数据

题目描述:请你写出更新语句,将所有获取奖金的员工当前的(salaries.to_date=‘9999-01-01’)薪水增加10%。(emp_bonus里面的emp_no都是当前获奖的所有员工)

UPDATE salaries
SET salary = salary * 1.1
WHERE to_date = '9999-01-01'
    AND emp_no IN (
        SELECT emp_no
        FROM emp_bonus)

猜你喜欢

转载自blog.csdn.net/qq_42820853/article/details/108816026