sql日常练习

  • 建表
Create Table

CREATE TABLE `emp` (
  `empno` int(11) DEFAULT NULL,
  `ename` varchar(50) DEFAULT NULL,
  `job` varchar(50) DEFAULT NULL,
  `mgr` int(11) DEFAULT NULL,
  `hiredate` date DEFAULT NULL,
  `sal` decimal(7,2) DEFAULT NULL,
  `comm` decimal(7,2) DEFAULT NULL,
  `deptno` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
  • 题目

1.
按照每个部门里最低薪水从高到低排序,求出最低薪水的人及其部门信息
SELECT *
FROM
(SELECT *
FROM emp
WHERE empno IN(
SELECT empno
FROM emp
WHERE (deptno,sal) IN(
SELECT deptno,MIN(sal)
FROM emp
GROUP BY deptno))) t LEFT JOIN dept
ON t.deptno = dept.deptno
order by sal DESC

2.
每个部门薪水的第二名
SELECT e.* 
FROM emp e,(
    SELECT a.deptno,max(a.sal) as sal
    FROM emp a
    WHERE a.sal<(SELECT max(sal) FROM emp WHERE deptno=a.deptno)
    GROUP BY deptno
)t
WHERE e.deptno=t.deptno and e.sal=t.sal
ORDER BY e.deptno

3.
查询各个部门薪资第2名到第3名的雇员信息及薪资
SELECT e1.*,e2.sal,COUNT(e2.sal)+1 cs
-- SELECT e1.ename,e2.ename
FROM emp e1
LEFT JOIN emp e2
ON e1.deptno=e2.deptno AND e1.sal < e2.sal
GROUP BY e1.deptno,e1.empno
HAVING cs=2 OR cs=3

4.
查询每个部门工资最高工资并按工资从高到低排序 
select max(sal) from emp group by deptno order by max(sal) DESC;

5.
找出每个部门工资的第二到第三名的人员信息。
SELECT t.empno,t.ename,t.job,t.mgr,t.hiredate,t.sal,t.comm,t.deptno,t.名次 FROM(SELECT * 
,IF(@prec=deptno,@rank:=@rank+1,@rank:=1) AS 名次,
@prec:=deptno 
FROM emp
ORDER BY deptno,sal DESC) t WHERE 名次 = '2' OR 名次 = '3';

SELECT * FROM emp
ORDER BY deptno,sal DESC;

6.
不同部门中同一个领导 并且今年在同一周过生日的员工
SELECT a.* FROM emp a,emp b WHERE a.deptno!=b.deptno AND a.mgr=b.mgr  AND WEEK(a.hiredate)=WEEK(b.hiredate)

7.
从所有部门入职最早的人中查出工资最高的
select *,max(sal) from emp where (deptno,hiredate) in (select deptno,min(hiredate) from emp group by deptno)
8.
求每个部门薪资最低的两个人(不包含奖金)
SET @prec := -1;
SELECT a.deptno, a.empno, a.ename, a.sal, a.rlev 
FROM (
    SELECT deptno, empno, ename, sal, IF(@prec = deptno, @rank := @rank+1, @rank := 1) AS rlev, @prec := deptno
    FROM emp
    ORDER BY deptno ASC, sal ASC
) AS a
WHERE a.rlev = 1 OR a.rlev = 2

9.
每个部门员工工资前两名姓名,薪资及其名次

SELECT * FROM
(SELECT *,IF(@pre=deptno,@rank:=@rank+1,@rank:=1) AS 排名,@pre:=deptno
FROM
(SELECT * FROM emp ORDER BY deptno,sal DESC)t)f
WHERE 排名=1 OR 排名=2

1.
按照各个部门中,工资+奖金超过本部门平均工资的员工数的比率从高到低,显示各部门详细信息
select dept.*,rate from(
select ttt.deptno,count1/count2 as rate
from(
select deptno,count(*) count1
from(
select emp.deptno from(
select deptno,avg(sal) avg from emp group by deptno) t,emp
where t.deptno = emp.deptno and (emp.sal+ifnull(comm,0)) > avg) tt
group by tt.deptno)as ttt LEFT JOIN
(select deptno,count(*) count2 from emp group by deptno ) as tttt
on ttt.deptno = tttt.deptno)ttttt,dept
where ttttt.deptno = dept.deptno
order by rate desc

2.
-- 对每个部门员工的薪水排序,并给出排名
-- 规则如下
-- KING2    7839    10    1
-- KING    7839    10    1
-- CLARK    7782    10    2
-- MILLER    7934    10    3
SELECT a.empno,a.ename,a.deptno,
if(@p=a.deptno,
if(@q=a.sal,@rank,@rank:=@rank+1),
@rank:=1 and @p:=a.deptno) as Rank,@q:=a.sal as sal
FROM emp a,(SELECT @rank:=0,@p:=-1,@q:=0)r
ORDER BY deptno,sal desc

3.
输出各个部门的部门号,部门名及各个部门薪资的中位数(保留两位小数)
SELECT dept.deptno,dept.dname, FORMAT(AVG(emp_v2.sal),2) avg_sal
FROM (
    SELECT *
    FROM (
        SELECT deptno, empno, ename, sal,
        IF(@currdept = deptno, @rating := @rating+1, @rating := 1) AS rating, 
        @currdept := deptno
        FROM emp
        ORDER BY deptno ASC, sal DESC
    ) emp_v1
    WHERE (deptno,rating) IN(
        SELECT deptno,FLOOR((COUNT(sal)+1)/2) rating
        FROM emp
        GROUP BY deptno
        UNION
        SELECT deptno,CEIL((COUNT(sal)+1)/2) rating
        FROM emp
        GROUP BY deptno
    )
) emp_v2
LEFT JOIN dept
ON emp_v2.deptno = dept.deptno
GROUP BY emp_v2.deptno

4.
查询每个部门入职最早的员工详细信息
select * from(select min(hiredate) h,deptno from emp group by deptno) a,emp where  emp.deptno=a.deptno and emp.hiredate=a.h;

5.
每个部门随机选出一个人表演节目(一共三个人)并且部门号为20的部门出的必须是经理
SELECT ename,deptno FROM (SELECT * FROM emp WHERE deptno = '10' ORDER BY RAND() LIMIT 1)t1 UNION
SELECT ename,deptno FROM (SELECT * FROM emp WHERE deptno = '20' AND ename IN (SELECT e1.ename FROM emp e1, emp e2 WHERE e1.empno =  e2.mgr GROUP BY e1.empno) ORDER BY RAND() LIMIT 1)t2 UNION
SELECT ename,deptno FROM (SELECT * FROM emp WHERE deptno = '30' ORDER BY RAND() LIMIT 1)t3

6.
查询员工编号连续且没工资的员工信息
SET @rownum :=0;
SET @rownum2:=0;

SELECT
    t2.*
FROM(
SELECT
    t1.*,
    @rownum :=@rownum+1 rownum,
    t1.empno - @rownum OFFSET
FROM
    emp t1
)t2
WHERE
    t2.offset
IN(
SELECT
    t4.offset
FROM(
SELECT
    t3.empno,
    @rownum2 :=@rownum2+1 rownum,
    t3.empno - @rownum2 OFFSET
FROM
    emp t3
)t4
GROUP BY
    t4.OFFSET
HAVING
    COUNT(*)>1
);

7.
查询每个部门中入职月份是这个月的的工资(工资加奖金)第二名
SELECT * FROM(SELECT *,IF(@prec=deptno,@rank:=@rank+1,@rank:=1) AS 名次,@prec:= deptno ,sal+IFNULL(comm,0) AS summ
FROM (SELECT * FROM emp WHERE MONTH(hiredate)=MONTH(CURDATE()))t ORDER BY deptno,summ)m WHERE 名次=2

8.
求出各部门工资最低的员工所对应经理的入职年份,统计出在该年份公司各部门的入职人数
(注:部门是固定的 4个  10代表java  20代表ios  30代表python  40代表html)
展示形式:
年份     java   ios   python   html
1980      3      5         6          5
1981      1      1         0          0

select s_year,sum(IFNULL(java,0)) as java,sum(IFNULL(ios,0)) as ios,sum(IFNULL(python,0)) as python,sum(IFNULL(html,0)) as html
FROM( 
select year(hiredate) as s_year ,
                    case deptno when 10 then count(*) END as java, 
                    case deptno when 20 then count(*) END as ios,
                    case deptno when 30 then count(*) END as python, 
                    case deptno when 40 then count(*) END as html
    from emp 
    where year(hiredate) IN (
                                    select distinct(year(emp.hiredate))
                                    from emp ,(
                                                            select empno,ename,mgr,sal,comm,salary,num
                                                            FROM (
                                                                        select empno,ename,mgr,sal,comm,salary,IF(@wee=deptno,@zzz:=@zzz+1,@zzz:=1) as num ,@wee:=deptno 
                                                                        FROM (
                                                                                    select * , sum(sal+IFNULL(comm,0)) as salary from emp group by empno ORDER BY sum(sal+IFNULL(comm,0)) ASC 
                                                                                    ) a1
                                                                        ORDER BY deptno , salary ASC ) a2
                                                            where num = 1 ) a3
                                    where a3.mgr = emp.empno group by emp.empno ) 
GROUP BY s_year,deptno
) tt
group by s_year

9.
求各部门比其经理薪资高的人员的信息
SELECT e1.*  FROM  emp e1 LEFT JOIN emp e2 ON e1.mgr=e2.empno WHERE e1.sal>e2.sal

 

 

题目一

编写一个 SQL 查询,查找Person 表中所有重复的电子邮箱。

示例:

+----+---------+
| Id | Email   |
+----+---------+
| 1  | [email protected] |
| 2  | [email protected] |
| 3  | [email protected] |
+----+---------+
根据以上输入,你的查询应返回以下结果:

+---------+
| Email   |
+---------+
| [email protected] |
+---------+

答案

```sql
SELECT Email
FROM Person
GROUP BY  Email
HAVING count(Email) > 1;
```

题目二 

这里有张World 表

+-----------------+------------+------------+--------------+---------------+
| name            | continent  | area       | population   | gdp           |
+-----------------+------------+------------+--------------+---------------+
| Afghanistan     | Asia       | 652230     | 25500100     | 20343000      |
| Albania         | Europe     | 28748      | 2831741      | 12960000      |
| Algeria         | Africa     | 2381741    | 37100000     | 188681000     |
| Andorra         | Europe     | 468        | 78115        | 3712000       |
| Angola          | Africa     | 1246700    | 20609294     | 100990000     |
+-----------------+------------+------------+--------------+---------------+
如果一个国家的面积超过300万平方公里,或者人口超过2500万,那么这个国家就是大国家。

编写一个SQL查询,输出表中所有大国家的名称、人口和面积。

例如,根据上表,我们应该输出:

+--------------+-------------+--------------+
| name         | population  | area         |
+--------------+-------------+--------------+
| Afghanistan  | 25500100    | 652230       |
| Algeria      | 37100000    | 2381741      |
+--------------+-------------+--------------+

```sql
SELECT name,
        population,
        area
FROM world
WHERE population >25000000
        OR area>3000000
```

题目三 

表 point 保存了一些点在 x 轴上的坐标,这些坐标都是整数。

写一个查询语句,找到这些点中最近两个点之间的距离。

| x |

|-----|

| -1 |

| 0 |

| 2 |

最近距离显然是 '1' ,是点 '-1' 和 '0' 之间的距离。所以输出应该如下:

| shortest|

|---------|

| 1 |

注意:每个点都与其他点坐标不同,表 table 不会有重复坐标出现。

进阶:如果这些点在 x 轴上从左到右都有一个编号,输出结果时需要输出最近点对的编号呢?

```sql
SELECT abs(p1.x-p2.x) AS shortest
FROM point p1, point p2
WHERE p1.x<>p2.x
ORDER BY  shortest limit 1;
```

题目四 

某城市开了一家新的电影院,吸引了很多人过来看电影。该电影院特别注意用户体验,专门有个 LED显示板做电影推荐,上面公布着影评和相关电影描述。

作为该电影院的信息部主管,您需要编写一个 SQL查询,找出所有影片描述为非 boring (不无聊) 的并且 id 为奇数 的影片,结果请按等级 rating 排列。

例如,下表 cinema:

+---------+-----------+--------------+-----------+

| id | movie | description | rating |

+---------+-----------+--------------+-----------+

| 1 | War | great 3D | 8.9 |

| 2 | Science | fiction | 8.5 |

| 3 | irish | boring | 6.2 |

| 4 | Ice song | Fantacy | 8.6 |

| 5 | House card| Interesting| 9.1 |

+---------+-----------+--------------+-----------+

对于上面的例子,则正确的输出是为:

+---------+-----------+--------------+-----------+

| id | movie | description | rating |

+---------+-----------+--------------+-----------+

| 5 | House card| Interesting| 9.1 |

| 1 | War | great 3D | 8.9 |

+---------+-----------+--------------+-----------+

```sql
SELECT *
FROM cinema
WHERE mod(id, 2) = 1
        AND description != 'boring'
ORDER BY  rating DESC ;
```

题目五 

在表 order 中找到订单数最多客户对应的 customer\_number 。

数据保证订单数最多的顾客恰好只有一位。

表 orders 定义如下:

| Column | Type |

|-------------------|-----------|

| order\_number (PK) | int |

| customer\_number | int |

| order\_date | date |

| required\_date | date |

| shipped\_date | date |

| status | char(15) |

| comment | char(200) |

样例输入

| order\_number | customer\_number | order\_date | required\_date | shipped\_date | status | comment |

|--------------|-----------------|------------|---------------|--------------|--------|---------|

| 1 | 1 | 2017-04-09 | 2017-04-13 | 2017-04-12 | Closed | |

| 2 | 2 | 2017-04-15 | 2017-04-20 | 2017-04-18 | Closed | |

| 3 | 3 | 2017-04-16 | 2017-04-25 | 2017-04-20 | Closed | |

| 4 | 3 | 2017-04-18 | 2017-04-28 | 2017-04-25 | Closed | |

样例输出

| customer\_number |

|-----------------|

| 3 |

解释

customer\_number 为 '3' 的顾客有两个订单,比顾客 '1' 或者 '2' 都要多,因为他们只有一个订单

所以结果是该顾客的 customer\_number ,也就是 3 。

进阶: 如果有多位顾客订单数并列最多,你能找到他们所有的 customer\_number 吗?

```sql
SELECT customer_number
FROM 
  (SELECT o.customer_number,
         count(1)
  FROM orders o
  GROUP BY  o.customer_number
  ORDER BY  count(1) DESC )
WHERE rownum = 1
```

题目六 

表1: Person

+-------------+---------+

| 列名 | 类型 |

+-------------+---------+

| PersonId | int |

| FirstName | varchar |

| LastName | varchar |

+-------------+---------+

PersonId 是上表主键

表2: Address

+-------------+---------+

| 列名 | 类型 |

+-------------+---------+

| AddressId | int |

| PersonId | int |

| City | varchar |

| State | varchar |

+-------------+---------+

AddressId 是上表主键

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

FirstName, LastName, City, State

```sql
SELECT FirstName,
         LastName,
         City,
         State
FROM Person
LEFT JOIN Address
    ON Person.PersonId = Address.PersonId;
```

题目七 

给定一个 salary 表,如下所示,有 m = 男性 和 f = 女性 的值。交换所有的 f 和 m 值(例如,将所有 f 值更改为 m,反之亦然)。要求只使用一个更新(Update)语句,并且没有中间的临时表。

注意,您必只能写一个 Update 语句,请不要编写任何 Select 语句。

例如:

| id | name | sex | salary |

|----|------|-----|--------|

| 1 | A | m | 2500 |

| 2 | B | f | 1500 |

| 3 | C | m | 5500 |

| 4 | D | f | 500 |

运行你所编写的更新语句之后,将会得到以下表:

| id | name | sex | salary |

|----|------|-----|--------|

| 1 | A | f | 2500 |

| 2 | B | m | 1500 |

| 3 | C | f | 5500 |

| 4 | D | m | 500 |

```sql
UPDATE salary SET sex =
    CASE sex
    WHEN 'm' THEN
    'f'
    ELSE 'm' END;
```

题目八

给定表 customer ,里面保存了所有客户信息和他们的推荐人。

+------+------+-----------+

| id | name | referee\_id|

+------+------+-----------+

| 1 | Will | NULL |

| 2 | Jane | NULL |

| 3 | Alex | 2 |

| 4 | Bill | NULL |

| 5 | Zack | 1 |

| 6 | Mark | 2 |

+------+------+-----------+

写一个查询语句,返回一个编号列表,列表中编号的推荐人的编号都 不是 2。

对于上面的示例数据,结果为:

+------+

| name |

+------+

| Will |

| Jane |

| Bill |

| Zack |

+------+

```sql
SELECT name
FROM customer
WHERE referee_id !=2
        OR referee_id is null
```

题目九

ActorDirector 表:

+-------------+---------+

| Column Name | Type |

+-------------+---------+

| actor\_id | int |

| director\_id | int |

| timestamp | int |

+-------------+---------+

timestamp 是这张表的主键.

写一条SQL查询语句获取合作过至少三次的演员和导演的 id 对 (actor\_id, director\_id)

示例:

ActorDirector 表:

+-------------+-------------+-------------+

| actor\_id | director\_id | timestamp |

+-------------+-------------+-------------+

| 1 | 1 | 0 |

| 1 | 1 | 1 |

| 1 | 1 | 2 |

| 1 | 2 | 3 |

| 1 | 2 | 4 |

| 2 | 1 | 5 |

| 2 | 1 | 6 |

+-------------+-------------+-------------+

Result 表:

+-------------+-------------+

| actor\_id | director\_id |

+-------------+-------------+

| 1 | 1 |

+-------------+-------------+

唯一的 id 对是 (1, 1),他们恰好合作了 3 次。

```sql
SELECT actor_id,
         director_id
FROM ActorDirector
GROUP BY  actor_id, director_id
HAVING count(*) >= 3;
```

题目十

几个朋友来到电影院的售票处,准备预约连续空余座位。

你能利用表 cinema ,帮他们写一个查询语句,获取所有空余座位,并将它们按照 seat\_id 排序后返回吗?

| seat\_id | free |

|---------|------|

| 1 | 1 |

| 2 | 0 |

| 3 | 1 |

| 4 | 1 |

| 5 | 1 |

对于如上样例,你的查询语句应该返回如下结果。

| seat\_id |

|---------|

| 3 |

| 4 |

| 5 |

注意:

seat\_id 字段是一个自增的整数,free 字段是布尔类型('1' 表示空余, '0' 表示已被占据)。

连续空余座位的定义是大于等于 2 个连续空余的座位。

```sql
SELECT seat_id
FROM 
  (SELECT seat_id,
         count(1)
      OVER (partition by offset) cnt
  FROM 
    (SELECT seat_id,
         (row_number()
        OVER (order by seat_id) - seat_id) offset
    FROM cinema
    WHERE free = 1 ) )
  WHERE cnt >= 2 -- 2改为N,可实现查找任意N个座位连续的记录。
ORDER BY  seat_id
```

题目十一 

选出所有 bonus \< 1000 的员工的 name 及其 bonus。

Employee 表单

+-------+--------+-----------+--------+

| empId | name | supervisor| salary |

+-------+--------+-----------+--------+

| 1 | John | 3 | 1000 |

| 2 | Dan | 3 | 2000 |

| 3 | Brad | null | 4000 |

| 4 | Thomas | 3 | 4000 |

+-------+--------+-----------+--------+

empId 是这张表单的主关键字

Bonus 表单

+-------+-------+

| empId | bonus |

+-------+-------+

| 2 | 500 |

| 4 | 2000 |

+-------+-------+

empId 是这张表单的主关键字

输出示例:

+-------+-------+

| name | bonus |

+-------+-------+

| John | null |

| Dan | 500 |

| Brad | null |

+-------+-------+

```sql
SELECT e.name,
        b.bonus
FROM Employee e
LEFT JOIN Bonus b
    ON e.empId = b.empId
WHERE ifnull(bonus,0)<1000
```

题目十二

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 |

+----------+

```sql
SELECT a.Name AS 'Employee'
FROM Employee AS a, Employee AS b
WHERE a.ManagerId = b.Id
        AND a.Salary > b.Salary ; 
```

题目十三

某网站包含两个表,Customers 表和 Orders 表。编写一个 SQL 查询,找出所有从不订购任何东西的客户。

Customers 表:

+----+-------+

| Id | Name |

+----+-------+

| 1 | Joe |

| 2 | Henry |

| 3 | Sam |

| 4 | Max |

+----+-------+

Orders 表:

+----+------------+

| Id | CustomerId |

+----+------------+

| 1 | 3 |

| 2 | 1 |

+----+------------+

例如给定上述表格,你的查询应返回:

+-----------+

| Customers |

+-----------+

| Henry |

| Max |

+-----------+

```sql
SELECT customers.name AS 'Customers'
FROM customers
WHERE customers.id NOT IN 
  (SELECT customerid
  FROM orders );
```

题目十四

一个小学生 Tim 的作业是判断三条线段是否能形成一个三角形。

然而,这个作业非常繁重,因为有几百组线段需要判断。

假设表 table 保存了所有三条线段的三元组 x, y, z ,你能帮 Tim 写一个查询语句,来判断每个三元组是否可以组成一个三角形吗?

| x | y | z |

|----|----|----|

| 13 | 15 | 30 |

| 10 | 20 | 15 |

对于如上样例数据,你的查询语句应该返回如下结果:

| x | y | z | triangle |

|----|----|----|----------|

| 13 | 15 | 30 | No |

| 10 | 20 | 15 | Yes |

```sql
SELECT *,
         if(x+y>z
        AND x+z>y
        AND y+z>x, 'Yes', 'No') AS triangle
FROM triangle;
```

题目十五 

描述

给定 3 个表: salesperson, company, orders。

输出所有表 salesperson 中,没有向公司 'RED' 销售任何东西的销售员。

解释

输入

表: salesperson

+----------+------+--------+-----------------+-----------+

| sales\_id | name | salary | commission\_rate | hire\_date |

+----------+------+--------+-----------------+-----------+

| 1 | John | 100000 | 6 | 4/1/2006 |

| 2 | Amy | 120000 | 5 | 5/1/2010 |

| 3 | Mark | 65000 | 12 | 12/25/2008|

| 4 | Pam | 25000 | 25 | 1/1/2005 |

| 5 | Alex | 50000 | 10 | 2/3/2007 |

+----------+------+--------+-----------------+-----------+

表 salesperson 存储了所有销售员的信息。每个销售员都有一个销售员编号 sales\_id 和他的名字 name 。

表: company

+---------+--------+------------+

| com\_id | name | city |

+---------+--------+------------+

| 1 | RED | Boston |

| 2 | ORANGE | New York |

| 3 | YELLOW | Boston |

| 4 | GREEN | Austin |

+---------+--------+------------+

表 company 存储了所有公司的信息。每个公司都有一个公司编号 com\_id 和它的名字 name 。

表: orders

+----------+------------+---------+----------+--------+

| order\_id | order\_date | com\_id | sales\_id | amount |

+----------+------------+---------+----------+--------+

| 1 | 1/1/2014 | 3 | 4 | 100000 |

| 2 | 2/1/2014 | 4 | 5 | 5000 |

| 3 | 3/1/2014 | 1 | 1 | 50000 |

| 4 | 4/1/2014 | 1 | 4 | 25000 |

+----------+----------+---------+----------+--------+

表 orders 存储了所有的销售数据,包括销售员编号 sales\_id 和公司编号 com\_id 。

输出

+------+

| name | 

+------+

| Amy | 

| Mark | 

| Alex |

+------+

解释

根据表 orders 中的订单 '3' 和 '4' ,容易看出只有 'John' 和 'Pam' 两个销售员曾经向公司 'RED' 销售过。

所以我们需要输出表 salesperson 中所有其他人的名字。

```sql
SELECT name
FROM salesperson
WHERE name NOT in
  (SELECT s.name
  FROM orders o
  JOIN company c
      ON c.com_id = o.com_id
  JOIN salesperson s
      ON s.sales_id = o.sales_id
  WHERE c.name='RED'
  GROUP BY  s.name ); 
```

题目十六

编写一个 SQL 查询,来删除 Person 表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个。

+----+------------------+

| Id | Email |

+----+------------------+

| 1 | [email protected] |

| 2 | [email protected] |

| 3 | [email protected] |

+----+------------------+

Id 是这个表的主键。

例如,在运行你的查询语句之后,上面的 Person 表应返回以下几行:

+----+------------------+

| Id | Email |

+----+------------------+

| 1 | [email protected] |

| 2 | [email protected] |

+----+------------------+

```sql
DELETE p1
FROM Person p1, Person p2
WHERE p1.Email = p2.Email
        AND p1.Id > p2.Id 
```

题目十七

给定一个 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 |

+----+

```sql
SELECT weather.id AS 'Id'
FROM weather
JOIN weather w
    ON DATEDIFF(weather.date, w.date) = 1
        AND weather.Temperature > w.Temperature ; 
```

题目二十

表 my\_numbers 的 num 字段包含很多数字,其中包括很多重复的数字。

你能写一个 SQL 查询语句,找到只出现过一次的数字中,最大的一个数字吗?

+---+

|num|

+---+

| 8 |

| 8 |

| 3 |

| 3 |

| 1 |

| 4 |

| 5 |

| 6 | 

对于上面给出的样例数据,你的查询语句应该返回如下结果:

+---+

|num|

+---+

| 6 |

```sql
SELECT ifnull( 
  (SELECT *
  FROM my_numbers
  GROUP BY  num
  HAVING count(*) = 1
  ORDER BY  num DESC limit 1),null) AS num 
```

题目二十一

有一个courses 表 ,有: student (学生) 和 class (课程)。

请列出所有超过或等于5名学生的课。

例如,表:

+---------+------------+

| student | class |

+---------+------------+

| A | Math |

| B | English |

| C | Math |

| D | Biology |

| E | Math |

| F | Computer |

| G | Math |

| H | Math |

| I | Math |

+---------+------------+

应该输出:

+---------+

| class |

+---------+

| Math |

+---------+

Note:

学生在每个课中不应被重复计算。

```sql
SELECT DISTINCT class
FROM courses
GROUP BY  class
HAVING COUNT(DISTINCT student)>=5;
```

题目二十二

在 Facebook 或者 Twitter 这样的社交应用中,人们经常会发好友申请也会收到其他人的好友申请。现在给如下两个表:

表: friend\_request

| sender\_id | send\_to\_id |request\_date|

|-----------|------------|------------|

| 1 | 2 | 2016\_06-01 |

| 1 | 3 | 2016\_06-01 |

| 1 | 4 | 2016\_06-01 |

| 2 | 3 | 2016\_06-02 |

| 3 | 4 | 2016-06-09 |

表: request\_accepted

| requester\_id | accepter\_id |accept\_date |

|--------------|-------------|------------|

| 1 | 2 | 2016\_06-03 |

| 1 | 3 | 2016-06-08 |

| 2 | 3 | 2016-06-08 |

| 3 | 4 | 2016-06-09 |

| 3 | 4 | 2016-06-10 |

写一个查询语句,求出好友申请的通过率,用 2 位小数表示。通过率由接受好友申请的数目除以申请总数。

对于上面的样例数据,你的查询语句应该返回如下结果。

|accept\_rate|

|-----------|

| 0.80|

注意:

通过的好友申请不一定都在表 friend\_request 中。在这种情况下,你只需要统计总的被通过的申请数(不管它们在不在原来的申请中),并将它除以申请总数,得到通过率

一个好友申请发送者有可能会给接受者发几条好友申请,也有可能一个好友申请会被通过好几次。这种情况下,重复的好友申请只统计一次。

如果一个好友申请都没有,通过率为 0.00 。

解释: 总共有 5 个申请,其中 4 个是不重复且被通过的好友申请,所以成功率是 0.80 。

进阶:

你能写一个查询语句得到每个月的通过率吗?

你能求出每一天的累计通过率吗?

```sql
SELECT (case
    WHEN q1=0 THEN
    round(0,2)
    ELSE round(q1/q2,2)
    END ) accept_rate from
  (SELECT count(*) q1 from
    (SELECT requester_id,
        accepter_id
    FROM request_accepted
    GROUP BY  requester_id,accepter_id)t1)t3, 
    (SELECT count(*) q2 from
      (SELECT sender_id,
        send_to_id
      FROM friend_request
      GROUP BY  sender_id,send_to_id)t2)t4 
```
 

 

 

 

 

 

你可能感兴趣的:(数据库)