141、求名次(1)
该题目使用的表和数据如下:
/*
drop table if exists `salaries` ;
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
INSERT INTO salaries VALUES(10001,60117,'1986-06-26','1987-06-26');
INSERT INTO salaries VALUES(10001,62102,'1987-06-26','1988-06-25');
INSERT INTO salaries VALUES(10001,66074,'1988-06-25','1989-06-25');
INSERT INTO salaries VALUES(10001,66596,'1989-06-25','1990-06-25');
INSERT INTO salaries VALUES(10001,66961,'1990-06-25','1991-06-25');
INSERT INTO salaries VALUES(10001,71046,'1991-06-25','1992-06-24');
INSERT INTO salaries VALUES(10001,74333,'1992-06-24','1993-06-24');
INSERT INTO salaries VALUES(10001,75286,'1993-06-24','1994-06-24');
INSERT INTO salaries VALUES(10001,75994,'1994-06-24','1995-06-24');
INSERT INTO salaries VALUES(10001,76884,'1995-06-24','1996-06-23');
INSERT INTO salaries VALUES(10001,80013,'1996-06-23','1997-06-23');
INSERT INTO salaries VALUES(10001,81025,'1997-06-23','1998-06-23');
INSERT INTO salaries VALUES(10001,81097,'1998-06-23','1999-06-23');
INSERT INTO salaries VALUES(10001,84917,'1999-06-23','2000-06-22');
INSERT INTO salaries VALUES(10001,85112,'2000-06-22','2001-06-22');
INSERT INTO salaries VALUES(10001,85097,'2001-06-22','2002-06-22');
INSERT INTO salaries VALUES(10001,88958,'2002-06-22','9999-01-01');
INSERT INTO salaries VALUES(10002,72527,'1996-08-03','1997-08-03');
INSERT INTO salaries VALUES(10002,72527,'1997-08-03','1998-08-03');
INSERT INTO salaries VALUES(10002,72527,'1998-08-03','1999-08-03');
INSERT INTO salaries VALUES(10002,72527,'1999-08-03','2000-08-02');
INSERT INTO salaries VALUES(10002,72527,'2000-08-02','2001-08-02');
INSERT INTO salaries VALUES(10002,72527,'2001-08-02','9999-01-01');
INSERT INTO salaries VALUES(10003,40006,'1995-12-03','1996-12-02');
INSERT INTO salaries VALUES(10003,43616,'1996-12-02','1997-12-02');
INSERT INTO salaries VALUES(10003,43466,'1997-12-02','1998-12-02');
INSERT INTO salaries VALUES(10003,43636,'1998-12-02','1999-12-02');
INSERT INTO salaries VALUES(10003,43478,'1999-12-02','2000-12-01');
INSERT INTO salaries VALUES(10003,43699,'2000-12-01','2001-12-01');
INSERT INTO salaries VALUES(10003,43311,'2001-12-01','9999-01-01');
*/
数据表:salaries,表中数据如下:
mysql> select * from salaries;
+--------+--------+------------+------------+
| emp_no | salary | from_date | to_date |
+--------+--------+------------+------------+
| 10001 | 60117 | 1986-06-26 | 1987-06-26 |
| 10001 | 62102 | 1987-06-26 | 1988-06-25 |
| 10001 | 66074 | 1988-06-25 | 1989-06-25 |
| 10001 | 66596 | 1989-06-25 | 1990-06-25 |
| 10001 | 66961 | 1990-06-25 | 1991-06-25 |
| 10001 | 71046 | 1991-06-25 | 1992-06-24 |
| 10001 | 74333 | 1992-06-24 | 1993-06-24 |
| 10001 | 75286 | 1993-06-24 | 1994-06-24 |
| 10001 | 75994 | 1994-06-24 | 1995-06-24 |
| 10001 | 76884 | 1995-06-24 | 1996-06-23 |
| 10001 | 80013 | 1996-06-23 | 1997-06-23 |
| 10001 | 81025 | 1997-06-23 | 1998-06-23 |
| 10001 | 81097 | 1998-06-23 | 1999-06-23 |
| 10001 | 84917 | 1999-06-23 | 2000-06-22 |
| 10001 | 85112 | 2000-06-22 | 2001-06-22 |
| 10001 | 85097 | 2001-06-22 | 2002-06-22 |
| 10001 | 88958 | 2002-06-22 | 9999-01-01 |
| 10002 | 72527 | 1996-08-03 | 1997-08-03 |
| 10002 | 72527 | 1997-08-03 | 1998-08-03 |
| 10002 | 72527 | 1998-08-03 | 1999-08-03 |
| 10002 | 72527 | 1999-08-03 | 2000-08-02 |
| 10002 | 72527 | 2000-08-02 | 2001-08-02 |
| 10002 | 72527 | 2001-08-02 | 9999-01-01 |
| 10003 | 40006 | 1995-12-03 | 1996-12-02 |
| 10003 | 43616 | 1996-12-02 | 1997-12-02 |
| 10003 | 43466 | 1997-12-02 | 1998-12-02 |
| 10003 | 43636 | 1998-12-02 | 1999-12-02 |
| 10003 | 43478 | 1999-12-02 | 2000-12-01 |
| 10003 | 43699 | 2000-12-01 | 2001-12-01 |
| 10003 | 43311 | 2001-12-01 | 9999-01-01 |
+--------+--------+------------+------------+
30 rows in set (0.00 sec)
【问题】查询当前员工(to_date = ‘9999-01-01’)的 emp_no,salary,salary 的累计和 running_total(running_total 为前 N 个的 salary 累计和),查询结果如下:
| emp_no | salary | running_total |
|---|---|---|
| 10001 | 88958 | 88958 |
| 10002 | 72527 | 161485 |
| 10003 | 43311 | 204796 |
解答:
/*
select emp_no, salary,
@sum_salary := @sum_salary + salary running_total
from salaries, (select @sum_salary := 0) a
where to_date = '9999-01-01';
*/
mysql> select emp_no, salary,
-> @sum_salary := @sum_salary + salary running_total
-> from salaries, (select @sum_salary := 0) a
-> where to_date = '9999-01-01';
+--------+--------+---------------+
| emp_no | salary | running_total |
+--------+--------+---------------+
| 10001 | 88958 | 88958 |
| 10002 | 72527 | 161485 |
| 10003 | 43311 | 204796 |
+--------+--------+---------------+
3 rows in set (0.00 sec)
/*
select a.emp_no, a.salary, sum(b.salary) running_total
from salaries a join salaries b on a.emp_no >= b.emp_no
where a.to_date = '9999-01-01' and b.to_date = '9999-01-01'
group by a.emp_no, a.salary;
*/
mysql> select a.emp_no, a.salary, sum(b.salary) running_total
-> from salaries a join salaries b on a.emp_no >= b.emp_no
-> where a.to_date = '9999-01-01' and b.to_date = '9999-01-01'
-> group by a.emp_no, a.salary;
+--------+--------+---------------+
| emp_no | salary | running_total |
+--------+--------+---------------+
| 10001 | 88958 | 88958 |
| 10002 | 72527 | 161485 |
| 10003 | 43311 | 204796 |
+--------+--------+---------------+
3 rows in set (0.00 sec)
142、求名次(2)
该题目使用的表和数据如下:
/*
drop table if exists `employees` ;
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`));
INSERT INTO employees VALUES(10001,'1953-09-02','Georgi','Facello','M','1986-06-26');
INSERT INTO employees VALUES(10002,'1964-06-02','Bezalel','Simmel','F','1985-11-21');
INSERT INTO employees VALUES(10005,'1955-01-21','Kyoichi','Maliniak','M','1989-09-12');
INSERT INTO employees VALUES(10006,'1953-04-20','Anneke','Preusig','F','1989-06-02');
*/
数据表:employees,表中数据如下:
mysql> select * from employees;
+--------+------------+------------+-----------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date |
+--------+------------+------------+-----------+--------+------------+
| 10001 | 1953-09-02 | Georgi | Facello | M | 1986-06-26 |
| 10002 | 1964-06-02 | Bezalel | Simmel | F | 1985-11-21 |
| 10005 | 1955-01-21 | Kyoichi | Maliniak | M | 1989-09-12 |
| 10006 | 1953-04-20 | Anneke | Preusig | F | 1989-06-02 |
+--------+------------+------------+-----------+--------+------------+
4 rows in set (0.00 sec)
【问题】查询 first_name 排名(按 first_name 升序排序)为奇数的 first_name,查询结果如下:
| first |
|---|
| Anneke |
| Georgi |
解答:
/*
select a.first_name first
from employees a join employees b on a.first_name >= b.first_name
group by a.first_name
having mod(count(*),2) = 1
order by a.first_name;
*/
mysql> select a.first_name first
-> from employees a join employees b on a.first_name >= b.first_name
-> group by a.first_name
-> having mod(count(*),2) = 1
-> order by a.first_name;
+--------+
| first |
+--------+
| Anneke |
| Georgi |
+--------+
2 rows in set (0.00 sec)
/*
select first from
(select first_name first, (select @rank := @rank + 1) rank
from employees, (select @rank := 0) a
order by first_name) b
where mod(rank, 2) = 1
order by first;
*/
mysql> select first from
-> (select first_name first, (select @rank := @rank + 1) rank
-> from employees, (select @rank := 0) a
-> order by first_name) b
-> where mod(rank, 2) = 1
-> order by first;
+--------+
| first |
+--------+
| Anneke |
| Georgi |
+--------+
2 rows in set (0.00 sec)
143、分组查询
该题目使用的表和数据如下:
/*
drop table if exists grade;
CREATE TABLE `grade` (
`id` int(4) NOT NULL,
`number` int(4) NOT NULL,
PRIMARY KEY (`id`));
INSERT INTO grade VALUES
(1,111),
(2,333),
(3,111),
(4,111),
(5,333);
*/
数据表:grade,表中数据如下:
mysql> select * from grade;
+----+--------+
| id | number |
+----+--------+
| 1 | 111 |
| 2 | 333 |
| 3 | 111 |
| 4 | 111 |
| 5 | 333 |
+----+--------+
5 rows in set (0.00 sec)
【问题】查询积分表中出现三次以及三次以上的积分,查询结果如下:
| number_cnt |
|---|
| 111 |
解答:
mysql> select number from grade group by number having count(*) >= 3;
+--------+
| number |
+--------+
| 111 |
+--------+
1 row in set (0.00 sec)
144、名次问题
该题目使用的表和数据如下:
/*
drop table if exists passing_number;
CREATE TABLE `passing_number` (
`id` int(4) NOT NULL,
`number` int(4) NOT NULL,
PRIMARY KEY (`id`));
INSERT INTO passing_number VALUES
(1,4),
(2,3),
(3,3),
(4,2),
(6,4),
(5,5);
*/
数据表:passing_number,表中数据如下:
mysql> select * from passing_number;
+----+--------+
| id | number |
+----+--------+
| 1 | 4 |
| 2 | 3 |
| 3 | 3 |
| 4 | 2 |
| 5 | 5 |
| 6 | 4 |
+----+--------+
6 rows in set (0.02 sec)
【问题】请根据上表,输出通过的题目的排名,通过题目个数相同的,排名相同,此时按照 id 升序排列,查询结果如下:
| id | number | t_rank |
|---|---|---|
| 5 | 5 | 1 |
| 1 | 4 | 2 |
| 6 | 4 | 2 |
| 2 | 3 | 3 |
| 3 | 3 | 3 |
| 4 | 2 | 4 |
解答:
/*
select p.id, p.number,
(select count(distinct number)+1 from passing_number where number > p.number) t_rank
from passing_number p
order by t_rank, p.id;
*/
mysql> select p.id, p.number,
-> (select count(distinct number)+1 from passing_number where number > p.number) t_rank
-> from passing_number p
-> order by t_rank, p.id;
+----+--------+--------+
| id | number | t_rank |
+----+--------+--------+
| 5 | 5 | 1 |
| 1 | 4 | 2 |
| 6 | 4 | 2 |
| 2 | 3 | 3 |
| 3 | 3 | 3 |
| 4 | 2 | 4 |
+----+--------+--------+
6 rows in set (0.00 sec)
/*
select p.id, p.number,
(select count(number)+1 from passing_number where number > p.number) t_rank
from passing_number p
order by t_rank, p.id;
*/
mysql> select p.id, p.number,
-> (select count(number)+1 from passing_number where number > p.number) t_rank
-> from passing_number p
-> order by t_rank, p.id;
+----+--------+--------+
| id | number | t_rank |
+----+--------+--------+
| 5 | 5 | 1 |
| 1 | 4 | 2 |
| 6 | 4 | 2 |
| 2 | 3 | 4 |
| 3 | 3 | 4 |
| 4 | 2 | 6 |
+----+--------+--------+
6 rows in set (0.00 sec)
145、外连接
该题目使用的表和数据如下:
/*
drop table if exists person;
drop table if exists task;
CREATE TABLE `person` (
`id` int(4) NOT NULL,
`name` varchar(32) NOT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `task` (
`id` int(4) NOT NULL,
`person_id` int(4) NOT NULL,
`content` varchar(32) NOT NULL,
PRIMARY KEY (`id`));
INSERT INTO person VALUES
(1,'fh'),
(2,'tm');
INSERT INTO task VALUES
(1,2,'tm works well'),
(2,2,'tm works well');
*/
person 表,主键为 id,表中数据如下:
mysql> select * from person;
+----+------+
| id | name |
+----+------+
| 1 | fh |
| 2 | tm |
+----+------+
2 rows in set (0.00 sec)
任务表:task,主键为id,表中数据如下:
mysql> select * from task;
+----+-----------+---------------+
| id | person_id | content |
+----+-----------+---------------+
| 1 | 2 | tm works well |
| 2 | 2 | tm works well |
+----+-----------+---------------+
2 rows in set (0.00 sec)
【问题】请查找每个人的任务情况并输出,没有任务的也要输出,输出结果按照 person 的 id 升序排序,查询结果如下:
| id | name | content |
|---|---|---|
| 1 | fh | NULL |
| 2 | tm | tm1 works well |
| 2 | tm | tm2 works well |
解答:
/*
select p.id, p.name, t.content
from person p left join task t on p.id = t.person_id
order by p.id;
*/
mysql> select p.id, p.name, t.content
-> from person p left join task t on p.id = t.person_id
-> order by p.id;
+----+------+---------------+
| id | name | content |
+----+------+---------------+
| 1 | fh | NULL |
| 2 | tm | tm works well |
| 2 | tm | tm works well |
+----+------+---------------+
3 rows in set (0.03 sec)
146、子连接
该题目使用的表和数据如下:
/*
drop table if exists email;
drop table if exists user;
CREATE TABLE `email` (
`id` int(4) NOT NULL,
`send_id` int(4) NOT NULL,
`receive_id` int(4) NOT NULL,
`type` varchar(32) NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `user` (
`id` int(4) NOT NULL,
`is_blacklist` int(4) NOT NULL,
PRIMARY KEY (`id`));
INSERT INTO email VALUES
(1,2,3,'completed','2020-01-11'),
(2,1,3,'completed','2020-01-11'),
(3,1,4,'no_completed','2020-01-11'),
(4,3,1,'completed','2020-01-12'),
(5,3,4,'completed','2020-01-12'),
(6,4,1,'completed','2020-01-12');
INSERT INTO user VALUES
(1,0),
(2,1),
(3,0),
(4,0);
*/
邮件表:email,id 为主键, type 是枚举类型,枚举成员为:completed,no_completed,completed 代表邮件发送是成功的,no_completed 代表邮件是发送失败的。表中数据如下:
mysql> select * from email;
+----+---------+------------+--------------+------------+
| id | send_id | receive_id | type | date |
+----+---------+------------+--------------+------------+
| 1 | 2 | 3 | completed | 2020-01-11 |
| 2 | 1 | 3 | completed | 2020-01-11 |
| 3 | 1 | 4 | no_completed | 2020-01-11 |
| 4 | 3 | 1 | completed | 2020-01-12 |
| 5 | 3 | 4 | completed | 2020-01-12 |
| 6 | 4 | 1 | completed | 2020-01-12 |
+----+---------+------------+--------------+------------+
6 rows in set (0.00 sec)
用户表:user,id 为主键(id 代表用户编号),is_blacklist 为 0 代表为正常用户,is_blacklist 为 1 代表为黑名单用户,表中数据如下::
ysql> select * from user;
+----+--------------+
| id | is_blacklist |
+----+--------------+
| 1 | 0 |
| 2 | 1 |
| 3 | 0 |
| 4 | 0 |
+----+--------------+
4 rows in set (0.00 sec)
【问题】请编写一个 SQL 查询,每一个日期里面,正常用户发送给正常用户邮件失败的概率是多少,结果保留到小数点后面 3 位(3 位之后的四舍五入),按照日期升序排序,查询结果如下:
| date | p |
|---|---|
| 2020-01-11 | 0.333 |
| 2020-01-12 | 0.000 |
解答:
/*
select e.date,
round(sum(if(send_id in (select id from user where is_blacklist = 0)
and receive_id in (select id from user where is_blacklist = 0)
and type = 'no_completed', 1, 0)) / count(*),3) p
from email e
group by e.date
order by e.date;
*/
mysql> select e.date,
-> round(sum(if(send_id in (select id from user where is_blacklist = 0)
-> and receive_id in (select id from user where is_blacklist = 0)
-> and type = 'no_completed', 1, 0)) / count(*),3) p
-> from email e
-> group by e.date
-> order by e.date;
+------------+-------+
| date | p |
+------------+-------+
| 2020-01-11 | 0.333 |
| 2020-01-12 | 0.000 |
+------------+-------+
2 rows in set (0.00 sec)
147、分组查询(1)
该题目使用的表和数据如下:
/*
drop table if exists login;
CREATE TABLE login (
id int(4) NOT NULL,
user_id int(4) NOT NULL,
client_id int(4) NOT NULL,
date date NOT NULL,
PRIMARY KEY (id));
INSERT INTO login VALUES
(1,2,1,'2020-10-12'),
(2,3,2,'2020-10-12'),
(3,2,2,'2020-10-13'),
(4,3,2,'2020-10-13');
*/
数据表:login,表中数据如下:
mysql> select * from login;
+----+---------+-----------+------------+
| id | user_id | client_id | date |
+----+---------+-----------+------------+
| 1 | 2 | 1 | 2020-10-12 |
| 2 | 3 | 2 | 2020-10-12 |
| 3 | 2 | 2 | 2020-10-13 |
| 4 | 3 | 2 | 2020-10-13 |
+----+---------+-----------+------------+
4 rows in set (0.00 sec)
【问题】请编写 SQL 语句查询每个用户最近一天登录的日子,按照 user_id 升序排序,查询结果如下:
| user_id | id |
|---|---|
| 2 | 2020-10-13 |
| 3 | 2020-10-13 |
解答:
/*
select user_id,max(date) id
from login
group by user_id
order by user_id;
*/
mysql> select user_id,min(date) id
-> from login
-> group by user_id
-> order by user_id;
+---------+------------+
| user_id | id |
+---------+------------+
| 2 | 2020-10-12 |
| 3 | 2020-10-12 |
+---------+------------+
2 rows in set (0.00 sec)
148、分组查询(2)
该题目使用的表和数据如下:
/*
drop table if exists login;
drop table if exists user;
drop table if exists client;
CREATE TABLE `login` (
`id` int(4) NOT NULL,
`user_id` int(4) NOT NULL,
`client_id` int(4) NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `user` (
`id` int(4) NOT NULL,
`name` varchar(32) NOT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `client` (
`id` int(4) NOT NULL,
`name` varchar(32) NOT NULL,
PRIMARY KEY (`id`));
INSERT INTO login VALUES
(1,2,1,'2020-10-12'),
(2,3,2,'2020-10-12'),
(3,2,2,'2020-10-13'),
(4,3,2,'2020-10-13');
INSERT INTO user VALUES
(1,'tm'),
(2,'fh'),
(3,'wangchao');
INSERT INTO client VALUES
(1,'pc'),
(2,'ios'),
(3,'anroid'),
(4,'h5');
*/
登录记录表:login,表中数据如下:
mysql> select * from login;
+----+---------+-----------+------------+
| id | user_id | client_id | date |
+----+---------+-----------+------------+
| 1 | 2 | 1 | 2020-10-12 |
| 2 | 3 | 2 | 2020-10-12 |
| 3 | 2 | 2 | 2020-10-13 |
| 4 | 3 | 2 | 2020-10-13 |
+----+---------+-----------+------------+
4 rows in set (0.00 sec)
用户表:user,表中数据如下:
mysql> select * from user;
+----+----------+
| id | name |
+----+----------+
| 1 | tm |
| 2 | fh |
| 3 | wangchao |
+----+----------+
3 rows in set (0.00 sec)
客户端表:client,表中数据如下:
mysql> select * from client;
+----+--------+
| id | name |
+----+--------+
| 1 | pc |
| 2 | ios |
| 3 | anroid |
| 4 | h5 |
+----+--------+
4 rows in set (0.00 sec)
【问题】请编写一个 SQL 语句查询每个用户最近一天登录的日子,用户的名字,以及用户使用的设备的名字,查询结果按照 user 的 name 升序排序,查询结果如下:
| u_n | c_n | date |
|---|---|---|
| fh | ios | 2020-10-13 |
| wangchao | ios | 2020-10-13 |
解答:
/*
select u_n, c.name c_n, a.date
from (select u.id, u.name u_n, max(date) date
from login l join user u on l.user_id = u.id
group by u.id, u_n) a join login l on a.id = l.user_id and a.date = l.date
join client c on l.client_id = c.id
order by u_n;
*/
mysql> select u_n, c.name c_n, a.date
-> from (select u.id, u.name u_n, max(date) date
-> from login l join user u on l.user_id = u.id
-> group by u.id, u_n) a join login l on a.id = l.user_id and a.date = l.date
-> join client c on l.client_id = c.id
-> order by c_n;
+----------+-----+------------+
| u_n | c_n | date |
+----------+-----+------------+
| wangchao | ios | 2020-10-13 |
| fh | ios | 2020-10-13 |
+----------+-----+------------+
2 rows in set (0.04 sec)
149、自连接查询(1)
该题目使用的表和数据如下:
/*
drop table if exists login;
CREATE TABLE `login` (
`id` int(4) NOT NULL,
`user_id` int(4) NOT NULL,
`client_id` int(4) NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`id`));
INSERT INTO login VALUES
(1,2,1,'2020-10-12'),
(2,3,2,'2020-10-12'),
(3,1,2,'2020-10-12'),
(4,2,2,'2020-10-13'),
(5,4,1,'2020-10-13'),
(6,1,2,'2020-10-13'),
(7,1,2,'2020-10-14');
*/
登录记录表:login,表中数据如下:
mysql> select * from login;
+----+---------+-----------+------------+
| id | user_id | client_id | date |
+----+---------+-----------+------------+
| 1 | 2 | 1 | 2020-10-12 |
| 2 | 3 | 2 | 2020-10-12 |
| 3 | 1 | 2 | 2020-10-12 |
| 4 | 2 | 2 | 2020-10-13 |
| 5 | 4 | 1 | 2020-10-13 |
| 6 | 1 | 2 | 2020-10-13 |
| 7 | 1 | 2 | 2020-10-14 |
+----+---------+-----------+------------+
7 rows in set (0.00 sec)
【问题】请统计新登录用户的次日成功的留存率,查询结果如下:
| p |
|---|
| 0.500 |
说明:
user_id 为 1 的用户在 2020-10-12 第一次新登录,在 2020-10-13 又登录了,为成功的留存。
user_id 为 2 的用户在 2020-10-12 第一次新登录,在 2020-10-13 又登录了,为成功的留存。
user_id 为 3 的用户在 2020-10-12 第一次新登录,在 2020-10-13 没登录了,为失败的留存。
user_id 为 4 的用户在 2020-10-13 第一次新登录,在 2020-10-14 没登录了,为失败的留存。
解答:
/*
select round((select count(*)
from login a join
(select user_id, min(date) first_login_date from login group by user_id) b
on a.user_id = b.user_id and adddate(a.date, -1) = first_login_date) /
(select count(distinct user_id) total_login from login),3) p;
*/
mysql> select round((select count(*)
-> from login a join
-> (select user_id, min(date) first_login_date from login group by user_id) b
-> on a.user_id = b.user_id and adddate(a.date, -1) = first_login_date) /
-> (select count(distinct user_id) total_login from login),3) p;
+-------+
| p |
+-------+
| 0.500 |
+-------+
1 row in set (0.03 sec)
150、自连接查询(2)
该题目使用的表和数据如下:
/*
drop table if exists login;
CREATE TABLE `login` (
`id` int(4) NOT NULL,
`user_id` int(4) NOT NULL,
`client_id` int(4) NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`id`));
INSERT INTO login VALUES
(1,2,1,'2020-10-12'),
(2,3,2,'2020-10-12'),
(3,1,2,'2020-10-12'),
(4,2,2,'2020-10-13'),
(5,1,2,'2020-10-13'),
(6,3,1,'2020-10-14'),
(7,4,1,'2020-10-14'),
(8,4,1,'2020-10-15');
*/
登录记录表:login,表中数据如下:
mysql> select * from login;
+----+---------+-----------+------------+
| id | user_id | client_id | date |
+----+---------+-----------+------------+
| 1 | 2 | 1 | 2020-10-12 |
| 2 | 3 | 2 | 2020-10-12 |
| 3 | 1 | 2 | 2020-10-12 |
| 4 | 2 | 2 | 2020-10-13 |
| 5 | 1 | 2 | 2020-10-13 |
| 6 | 3 | 1 | 2020-10-14 |
| 7 | 4 | 1 | 2020-10-14 |
| 8 | 4 | 1 | 2020-10-15 |
+----+---------+-----------+------------+
8 rows in set (0.00 sec)
【问题】请编写一个 SQL 语句,查询每个日期登录新用户个数,查询结果按照日期升序排序,查询结果如下:
| date | new |
|---|---|
| 2020-10-12 | 3 |
| 2020-10-13 | 0 |
| 2020-10-14 | 1 |
| 2020-10-15 | 0 |
解答:
/*
select date, count(b.user_id) new
from login a left join
(select user_id, min(date) first_login_date from login group by user_id) b
on a.user_id = b.user_id and a.date = b.first_login_date
group by date
order by date;
*/
mysql> select date, count(b.user_id) new
-> from login a left join
-> (select user_id, min(date) first_login_date from login group by user_id) b
-> on a.user_id = b.user_id and a.date = b.first_login_date
-> group by date
-> order by date;
+------------+-----+
| date | new |
+------------+-----+
| 2020-10-12 | 3 |
| 2020-10-13 | 0 |
| 2020-10-14 | 1 |
| 2020-10-15 | 0 |
+------------+-----+
4 rows in set (0.02 sec)