4.1 MySQL 實戰
學習內容
數據導入導出
將之前創建的任意一張MySQL表導出,且是CSV格式
關於csv文件,navicat for mysql中不包含cav文件的格式。嘗試用MySQL workbench,可以導出csv文件。
再將CSV表導入數據庫
使用sql語句:
導出
/*
字段之間以逗號分隔;字符串以半角雙引號包圍,字符串本身的雙引號用兩個雙引號表示。
數據行之間以\r\n分隔;
*/
select * from test_info
into outfile 'test.csv'
fields terminated by ',' optionally enclosed by '"' escaped by '"'
lines terminated by '\r\n';
導入
load data infile 'test.csv'
into table test_info
fields terminated by ',' optionally enclosed by '"' escaped by '"'
lines terminated by '\r\n';
作業
項目七: 各部門工資最高的員工(難度:中等)
創建Employee 表,包含所有員工信息,每個員工有其對應的 Id, salary 和 department Id。
+----+-------+--------+--------------+
| Id | Name | Salary | DepartmentId |
+----+-------+--------+--------------+
| 1 | Joe | 70000 | 1 |
| 2 | Henry | 80000 | 2 |
| 3 | Sam | 60000 | 2 |
| 4 | Max | 90000 | 1 |
+----+-------+--------+--------------+
創建Department 表,包含公司所有部門的信息。
+----+----------+
| Id | Name |
+----+----------+
| 1 | IT |
| 2 | Sales |
+----+----------+
編寫一個 SQL 查詢,找出每個部門工資最高的員工。例如,根據上述給定的表格,Max 在 IT 部門有最高工資,Henry 在 Sales 部門有最高工資。
USE test
CREATE TABLE IF NOT EXISTS Employee(
Id INT UNSIGNED AUTO_INCREMENT,
Name VARCHAR(100) NOT NULL,
Salary INT DEFAULT 0,
DepartmentId INT DEFAULT 0,
PRIMARY KEY (Id)
);
INSERT INTO Employee(Name,Salary,DepartmentId)
VALUES('Joe',70000,1),
('Henry',80000,2),
('Sam',60000,2),
('Max',90000,1);
USE test
CREATE TABLE IF NOT EXISTS Department(
Id INT UNSIGNED AUTO_INCREMENT,
Name VARCHAR(100) NOT NULL,
PRIMARY KEY (Id)
);
INSERT INTO Department(Name)
VALUES('IT'),
('Sales');
select d.Name as Department,e.Name as Employee,e.Salary
from Department d,Employee e
where e.DepartmentId=d.Id and e.Salary=(Select max(Salary) from Employee where DepartmentId=d.Id)
篩選結果
+------------+----------+--------+
| Department | Employee | Salary |
+------------+----------+--------+
| IT | Max | 90000 |
| Sales | Henry | 80000 |
+------------+----------+--------+
項目八: 換座位(難度:中等)
小美是一所中學的信息科技老師,她有一張 seat 座位表,平時用來儲存學生名字和與他們相對應的座位 id。
其中縱列的 id 是連續遞增的
小美想改變相鄰倆學生的座位。
你能不能幫她寫一個 SQL query 來輸出小美想要的結果呢?
請創建如下所示seat表:
示例:
+---------+---------+
| id | student |
+---------+---------+
| 1 | Abbot |
| 2 | Doris |
| 3 | Emerson |
| 4 | Green |
| 5 | Jeames |
+---------+---------+
假如數據輸入的是上表,則輸出結果如下:
+---------+---------+
| id | student |
+---------+---------+
| 1 | Doris |
| 2 | Abbot |
| 3 | Green |
| 4 | Emerson |
| 5 | Jeames |
+---------+---------+
注意:
如果學生人數是奇數,則不需要改變最後一個同學的座位。
USE test
CREATE TABLE IF NOT EXISTS Seat(
id INT UNSIGNED AUTO_INCREMENT,
student VARCHAR(100) NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO Seat(student)
VALUES('Adbot'),('Doris'),('Emerson'),('Green'),('James');
select s.id , s.student from
(
select id-1 as id ,student from seat where mod(id,2)=0
union
select id+1 as id,student from seat where mod(id,2)=1 and id !=(select count(*) from seat)
union
select id,student from seat where mod(id,2)=1 and id = (select count(*) from seat)
) s order by id;
項目九: 分數排名(難度:中等)
編寫一個 SQL 查詢來實現分數排名。如果兩個分數相同,則兩個分數排名(Rank)相同。請注意,平分後的下一個名次應該是下一個連續的整數值。換句話說,名次之間不應該有“間隔”。
創建以下score表:
+----+-------+
| Id | Score |
+----+-------+
| 1 | 3.50 |
| 2 | 3.65 |
| 3 | 4.00 |
| 4 | 3.85 |
| 5 | 4.00 |
| 6 | 3.65 |
+----+-------+
例如,根據上述給定的 Scores 表,你的查詢應該返回(按分數從高到低排列):
+-------+------+
| Score | Rank |
+-------+------+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
+-------+------+
sql語句
USE test
CREATE TABLE IF NOT EXISTS Scores(
Id INT UNSIGNED AUTO_INCREMENT,
Score FLOAT(5,2) NOT NULL,
PRIMARY KEY (Id)
);
INSERT INTO Scores(Score)
VALUES(3.50),(3.65),(4.00),(3.85),(4.00),(3.65);
select Score,
(select count(distinct Score) from Scores as s2 where s2.Score >= s1.Score) Rank
from Scores as s1
order by Score DESC;
4.2 MySQL 實戰 - 複雜項目
項目十:行程和用戶(難度:困難)
Trips 表中存所有出租車的行程信息。每段行程有唯一鍵 Id,Client_Id 和 Driver_Id 是 Users 表中 Users_Id 的外鍵。Status 是枚舉類型,枚舉成員爲 (‘completed’, ‘cancelled_by_driver’, ‘cancelled_by_client’)。
Id | Client_Id | Driver_Id | City_Id | Status | Request_at |
---|---|---|---|---|---|
1 | 1 | 10 | 1 | completed | 2013-10-01 |
2 | 2 | 11 | 1 | cancelled_by_driver | 2013-10-01 |
3 | 3 | 12 | 6 | completed | 2013-10-01 |
4 | 4 | 13 | 6 | cancelled_by_client | 2013-10-01 |
5 | 1 | 10 | 1 | completed | 2013-10-02 |
6 | 2 | 11 | 6 | completed | 2013-10-02 |
7 | 3 | 12 | 6 | completed | 2013-10-02 |
8 | 2 | 12 | 12 | completed | 2013-10-03 |
9 | 3 | 10 | 12 | completed | 2013-10-03 |
10 | 4 | 13 | 12 | cancelled_by_driver | 2013-10-03 |
Users 表存所有用戶。每個用戶有唯一鍵 Users_Id。Banned 表示這個用戶是否被禁止,Role 則是一個表示(‘client’, ‘driver’, ‘partner’)的枚舉類型。
+----------+--------+--------+
| Users_Id | Banned | Role |
+----------+--------+--------+
| 1 | No | client |
| 2 | Yes | client |
| 3 | No | client |
| 4 | No | client |
| 10 | No | driver |
| 11 | No | driver |
| 12 | No | driver |
| 13 | No | driver |
+----------+--------+--------+
寫一段 SQL 語句查出 2013年10月1日 至 2013年10月3日 期間非禁止用戶的取消率。基於上表,你的 SQL 語句應返回如下結果,取消率(Cancellation Rate)保留兩位小數。
+------------+-------------------+
| Day | Cancellation Rate |
+------------+-------------------+
| 2013-10-01 | 0.33 |
| 2013-10-02 | 0.00 |
| 2013-10-03 | 0.50 |
+------------+-------------------+
sql語句
USE test
CREATE TABLE IF NOT EXISTS Users(
Users_Id INT DEFAULT 0,
Banned VARCHAR(100) NOT NULL,
Role ENUM('client','driver','partner') DEFAULT 'client'
);
INSERT INTO Users(Users_Id,Banned,Role)
VALUES(1,'NO','client'),(2,'Yes','client'),(3,'NO','client'),(4,'NO','client'),
(10,'NO','driver'),(11,'NO','driver'),(12,'NO','driver'),(13,'NO','driver');
SELECT Request_at Day,
ROUND(COUNT(IF(Status != 'completed', TRUE, NULL)) / COUNT(*), 2) 'Cancellation Rate'
FROM Trips
WHERE (Request_at between '2013-10-01' and '2013-10-03') and Client_Id IN (SELECT Users_Id FROM Users WHERE Banned = 'No')
GROUP BY Request_at;
項目十一:各部門前3高工資的員工(難度:中等)
將項目7中的employee表清空,重新插入以下數據(其實是多插入5,6兩行):
Id | Name | Salary | DepartmentId |
---|---|---|---|
1 | Joe | 70000 | 1 |
2 | Henry | 80000 | 2 |
3 | Sam | 60000 | 2 |
4 | Max | 90000 | 1 |
5 | Janet | 69000 | 1 |
6 | Randy | 85000 | 1 |
編寫一個 SQL 查詢,找出每個部門工資前三高的員工。例如,根據上述給定的表格,查詢結果應返回:
Department | Employee | Salary |
---|---|---|
IT | Max | 90000 |
IT | Randy | 85000 |
IT | Joe | 70000 |
Sales | Henry | 80000 |
Sales | Sam | 60000 |
此外,請考慮實現各部門前N高工資的員工功能。
SELECT P2.Name AS Department,P3.Name AS Employee,P3.Salary AS Salary
FROM Employee AS P3
INNER JOIN Department AS P2
ON P2.Id = P3.DepartmentId
WHERE (
SELECT COUNT(DISTINCT Salary)
FROM Employee AS P4
WHERE P3.DepartmentId = P4.DepartmentId
AND P4.Salary >= P3.Salary
) <= 3
ORDER BY DepartmentId,Salary DESC
項目十二 分數排名 - (難度:中等)
依然是昨天的分數表,實現排名功能,但是排名是非連續的,如下:
Score | Rank |
---|---|
4.00 | 1 |
4.00 | 1 |
3.85 | 3 |
3.65 | 4 |
3.65 | 4 |
3.50 | 6 |
sql語句
SELECT Score,
(SELECT COUNT(Score)
FROM score AS s2
WHERE s2.Score > s1.Score
)+1 AS rank
FROM score AS s1
ORDER BY Score DESC;