mysql task06(结营)

目录

SQL编程语言课程学习心得

练习一: 各部门工资最高的员工(难度:中等)

练习二: 换座位(难度:中等)

练习三: 分数排名(难度:中等)

练习四:连续出现的数字(难度:中等)

练习五:树节点 (难度:中等)

练习六:至少有五名直接下属的经理 (难度:中等)

练习七:查询回答率最高的问题 (难度:中等)

练习八:各部门前3高工资的员工(难度:中等)

练习九:平面上最近距离 (难度: 困难)

练习十:行程和用户(难度:困难)


SQL编程语言课程学习心得

第一次参加datawhale的课程学习,这种线上组队、打卡自学的模式对我来说挺合适的,也让我开始尝试写自己的博客来输出内容(虽然现在的博客基本上是练习题,但也是一个新的开始)。比较可惜的是,我与其他组员的交流不够多,有点自闭(以后肯定要尝试多与小伙伴交流)。

课程的内容以及安排还是很合理的,就本次SQL的学习来说,我确实是零基础开始,一步步跟着课程任务进行学习,目前也算是掌握了一定的SQL知识,可以编程解决一些简单的问题。task01搭建环境时,由于我对各种客户端的使用方式不够了解,还是花了一定的功夫才上手,后续除了部分难点可能还未理解透彻,其他的内容基本可以跟上。

在此还是特别感谢datawhale团队的成员,提供了优质的开源学习内容,学习模式也很棒!以后会继续参加其他课程的学习。如果有什么建议的话,希望能营造一个更加积极的交流氛围吧。

以下练习题仅含sectionA的十道题,由于时间问题,剩余的练习无法在限定时间内完成,但是后续我还会继续练习,争取能够熟练运用基础的SQL语句。部分题目有一定难度,参考了网络。

练习一: 各部门工资最高的员工(难度:中等)


#1.创建Employee 表,包含所有员工信息,每个员工有其对应的 Id, salary 和 department Id。
#创建表

CREATE TABLE employee
(Id INT NOT NULL,
 NAME VARCHAR(8),
 salary INT,
 Department_ID INT NOT NULL);

#插入数值

INSERT INTO Employee
VALUES (1, "joe", 70000, 1),
       (2, "Henry", 80000, 2),
       (3, "Sam", 60000, 2),
       (4, "Max", 90000, 1);

#2.创建Department 表,包含公司所有部门的信息。

CREATE TABLE Department
(Id   INT NOT NULL,
 NAME VARCHAR(20));
INSERT INTO Department
VALUES (1, "IT"),
       (2, "Sales");

#3.编写一个 SQL 查询,找出每个部门工资最高的员工。例如,根据上述给定的表格,Max 在 IT 部门有最高工资,Henry 在 Sales 部门有最高工资。       
#思路:先找到各部门最高薪水,然后连接两张表并根据两张表的关系进行合并。

SELECT D.name AS Department, e.name AS Employee, salary
FROM Employee AS e
LEFT JOIN Department D
ON e.Department_ID = D.Id
WHERE (e.Department_ID, e.salary) 
IN (SELECT Department_ID, MAX(salary) AS "max_slary"
FROM Employee
GROUP BY Department_ID)

练习二: 换座位(难度:中等)


/*小美是一所中学的信息科技老师,她有一张 seat 座位表,平时用来储存学生名字和与他们相对应的座位 id。
其中纵列的id是连续递增的
小美想改变相邻俩学生的座位。
你能不能帮她写一个 SQL query 来输出小美想要的结果呢?
注意:如果学生人数是奇数,则不需要改变最后一个同学的座位。*/

#1.创建座位表,插入数值

CREATE TABLE seat
(id INT NOT NULL,
 student VARCHAR(10));
INSERT INTO seat
VALUES (1, "Abbot"),
       (2, "Doris"),
       (3, "Emerson"),
       (4, "Green"),
       (5, "jeames");

#2.改变相邻俩学生的座位
#关键点:学生人数是奇数不改变最后一个同学的座位,需要增加条件id != (SELECT COUNT(*) FROM seat)。

SELECT CASE
WHEN MOD(id, 2) != 0 AND id != (SELECT COUNT(*) FROM seat) THEN id + 1
WHEN MOD(id, 2) = 0 THEN id - 1
ELSE id
END AS "id", student
FROM seat ORDER BY id;

 
练习三: 分数排名(难度:中等)

 
#假设在某次期末考试中,二年级四个班的平均成绩分别是 93、93、93、91,请问可以实现几种排名结果?分别使用了什么函数?排序结果是怎样的?(只考虑降序)

CREATE TABLE Score
(class INT NOT NULL,
 score_avg INT);
INSERT INTO Score
VALUES (1, 93),(2, 93),(3, 93),(4, 91),(5, 96);

#法一、RANK函数:计算排序时,如果存在相同位次的记录,则会跳过之后的位次。

SELECT class, score_avg, RANK() OVER (ORDER BY score_avg DESC) AS ranking
FROM Score;

#法二:DENSE_RANK函数:同样是计算排序,即使存在相同位次的记录,也不会跳过之后的位次。

SELECT class, score_avg, DENSE_RANK() OVER (ORDER BY score_avg DESC) AS ranking
FROM Score;

#法三:ROW_NUMBER函数:赋予唯一的连续位次。

SELECT class, score_avg, ROW_NUMBER() OVER (ORDER BY score_avg DESC) AS ranking
FROM Score;


练习四:连续出现的数字(难度:中等)


#编写一个 SQL 查询,查找所有至少连续出现三次的数字。

CREATE TABLE nums_arr
(Id  INT NOT NULL,
 Num INT);
INSERT INTO nums_arr
VALUES (1, 1),(2, 1),(3, 1),(4, 2),(5, 1),(6, 2),(7, 2)

#思路:构建新列cut,为原id与根据数字排序建立的新id的差值,当相同的差值大于等于3时,即数字连续出现三次以上。
#id:     1 2 3 4 5 6 7
#num:    1 1 1 2 1 2 2
#new_id: 1 2 3 1 4 2 3
#cut:    0 0 0 3 1 4 4
#注:PARTITON BY分组时不会改变原始表中记录的行数。

SELECT Num AS ConsecutiveNums
FROM (SELECT Num, COUNT(*) FROM 
(SELECT Id, Num,
 id - (ROW_NUMBER() OVER (PARTITION BY Num ORDER BY id)) AS cut
 FROM nums_arr) AS sub
GROUP BY cut
HAVING COUNT(*) >= 3) AS Result;


练习五:树节点 (难度:中等)


/*对于tree表,id是树节点的标识,p_id是其父节点的id。
每个节点都是以下三种类型中的一种:
Root: 如果节点是根节点。
Leaf: 如果节点是叶子节点。
Inner: 如果节点既不是根节点也不是叶子节点。
节点’1’是根节点,因为它的父节点为NULL,有’2’和’3’两个子节点。
节点’2’是内部节点,因为它的父节点是’1’,有子节点’4’和’5’。
节点’3’,’4’,’5’是叶子节点,因为它们有父节点但没有子节点。*/

DROP TABLE tree
CREATE TABLE tree
(id   INT NOT NULL,
 p_id CHAR(8));
INSERT INTO tree
VALUES (1, NULL),(2, 1),(3, 1),(4, 2),(5, 2);

#法一、CASE WHEN语句

SELECT id, CASE
WHEN p_id IS NULL THEN "root"
WHEN id IN (SELECT DISTINCT p_id FROM tree) THEN "inner"
ELSE "leat"
END AS "type"
FROM tree;

#法二、if语句:SELECT IF(判别表达式,'yes','no')

SELECT id,
IF(ISNULL(p_id), "root",
IF(id IN (SELECT DISTINCT p_id FROM tree),"inner", "leaf")) AS "Type"
FROM tree;


练习六:至少有五名直接下属的经理 (难度:中等)

#Employee表包含所有员工及其上级的信息。每位员工都有一个Id,并且还有一个对应主管的Id(ManagerId)。

CREATE TABLE employee2
(id         INT NOT NULL,
 NAME       VARCHAR(10),
 department VARCHAR(10),
 manager_id INT,
 PRIMARY KEY (id));
INSERT INTO employee2
VALUES (101, "John", "A", NULL),
       (102, "Dan", "A", 101),
       (103, "James", "A", 101),
       (104, "Amy", "A", 101),
       (105, "Ron", "B", 101),
       (106, "Anne", "B", 101);

#内连接:INNER JOIN

SELECT t2.name
FROM employee2 t1
INNER JOIN employee2 AS t2
ON t1.manager_id = t2.id
GROUP BY t2.name
HAVING COUNT(1) >= 5;


练习七:查询回答率最高的问题 (难度:中等)


/*求出survey_log表中回答率最高的问题,表格的字段有:uid, action, question_id, answer_id, q_num, timestamp。
uid是用户id;action的值为:“show”, “answer”, “skip”;
当action是"answer"时,answer_id不为空,相反,当action是"show"和"skip"时为空(null);q_num是问题的数字序号。
写一条sql语句找出回答率(show 出现次数 / answer 出现次数)最高的 question_id。*/

CREATE TABLE survey_log
(uid CHAR(4) NOT NULL,
 ACTION VARCHAR(32) NOT NULL,
 question_id INTEGER,
 answer_id INTEGER,
 q_num INTEGER,
 TIMESTAMP INTEGER);
INSERT INTO survey_log 
VALUES ('5', 'show', 285, NULL, 1, 123),
       ('5', 'answer', 285, 1, 1, 124),
       ('5', 'show', 369, NULL, 2, 125),
       ('5', 'skip', 369, NULL, 2, 126);

#注:limit可以选择哪一行的数据,1就是前一行,(1,10就是从2开始选择10行数据),10就是前10行数据

SELECT question_id FROM
(SELECT question_id, 
 SUM(CASE WHEN ACTION = 'show' THEN 1
    ELSE 0
    END) / SUM(CASE
               WHEN ACTION = 'answer' THEN 1
               ELSE 0
               END) AS ratio
 FROM survey_log
 GROUP BY question_id
 ORDER BY ratio DESC 
 LIMIT 1) AS a;


#问题285的回答率为1/1,然而问题369的回答率是0/1,所以输出是285。

练习八:各部门前3高工资的员工(难度:中等)


#复制练习一中的 employee 表,再插入第5、第6行数据

INSERT INTO Employee
VALUES (5, "Janet", 69000, 1),
       (6, "Randy", 85000, 1);

#思路:先拼接Employee表和Department表,然后根据Department_ID分组后进行排序,最后找出前3名。

SELECT Department, NAME AS Employee, salary FROM
(SELECT salary, E.Name AS NAME,
 D.Name AS Department,
 DENSE_RANK() OVER (PARTITION BY Department_ID ORDER BY salary DESC) AS ranking
 FROM Employee AS E
 LEFT JOIN Department AS D
 ON E.Department_ID = D.Id) AS sub
WHERE ranking <= 3;


 

#此外,请考虑实现各部门前N高工资的员工功能。
#答:只需修改最后一个语句的参数即可,WHERE ranking <= N。


练习九:平面上最近距离 (难度: 困难)


#point_2d表包含一个平面内一些点(超过两个)的坐标值(x,y)。写一条查询语句求出这些点中的最短距离并保留2位小数。

CREATE TABLE point_2d
(X INT,
 Y INT);
INSERT INTO point_2d
VALUES (-1, -1),(0, 0),(-1, -2);

#计算距离,采用交叉连结:CROSS JOIN
#ROUND:保留小数的位数;SQRT:开方;POWER(X,Y) 返回底数为X,指数为Y的值

SELECT ROUND(MIN(SQRT(POW(p1.x - p2.x, 2) + POW((p1.y - p2.y), 2))), 2) AS shortest
FROM point_2d AS p1
CROSS JOIN point_2d AS p2
WHERE p1.x < p2.x OR p1.y < p2.y;


练习十:行程和用户(难度:困难)


/*数据背景:
Trips 表中存所有出租车的行程信息。每段行程有唯一键 Id,Client_Id 和 Driver_Id 是 Users 表中 Users_Id 的外键。
Status 是枚举类型,枚举成员为 (‘completed’, ‘cancelled_by_driver’, ‘cancelled_by_client’)。
Users 表存所有用户。每个用户有唯一键 Users_Id。
Banned 表示这个用户是否被禁止,Role 则是一个表示(‘client’, ‘driver’, ‘partner’)的枚举类型。
题目:写一段 SQL 语句查出2013年10月1日至2013年10月3日期间非禁止用户的取消率。
基于上表,你的 SQL 语句应返回如下结果,取消率(Cancellation Rate)保留两位小数。*/

#1.创建Trips表,插入数据

CREATE TABLE Trips 
(id INTEGER NOT NULL,
 client_id CHAR(4) NOT NULL,
 driver_id CHAR(4) NOT NULL,
 city_id CHAR(4) NOT NULL,
 STATUS VARCHAR(32),
 request_at DATE,
 PRIMARY KEY (id));
INSERT INTO trips VALUES ('1', '1', '10', '1', 'completed', '2013-10-1'),
             ('2', '2', '11', '1', 'cancelled_by_driver', '2013-10-1'),
                         ('3', '3', '12', '6', 'completed', '2013-10-1'),
                         ('4', '4', '13', '6', 'cancelled_by_client', '2013-10-1'),
                         ('5', '1', '10', '1', 'completed', '2013-10-2'),
                         ('6', '2', '11', '6', 'completed', '2013-10-2'),
                         ('7', '3', '12', '6', 'completed', '2013-10-2'),
                         ('8', '2', '12', '12', 'completed', '2013-10-3'),
                         ('9', '3', '10', '12', 'completed', '2013-10-3'),
                         ('10', '4', '13', '12', 'cancelled_by_driver', '2013-10-3');

#2.创建Users表,插入数据

CREATE TABLE Users 
(users_id INTEGER NOT NULL,
 banned VARCHAR(32) NOT NULL,
 ROLE VARCHAR(32) NOT NULL,
 PRIMARY KEY (users_id));
INSERT INTO users 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');

#3.连结两表

SELECT *
FROM Trips AS t
LEFT JOIN Users AS u
ON u.users_id = t.client_id
WHERE banned != "Yes" AND request_at BETWEEN 20131001 AND 20131003;

#4.查出指定期间非禁止用户的取消率

SELECT request_at AS "Day", ROUND(AVG(STATUS != "completed"), 2) AS 'Cancellation Rate'
FROM Trips AS t
LEFT JOIN Users AS u
ON u.users_id = t.client_id
WHERE banned != "Yes" AND request_at BETWEEN 20131001 AND 20131003
GROUP BY request_at
ORDER BY request_at;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值