LeetCode数据库SQL练习(九)

181 阅读12分钟

每个帖子的评论数

表 Submissions 结构如下:

+---------------+----------+
| 列名           | 类型     |
+---------------+----------+
| sub_id        | int      |
| parent_id     | int      |
+---------------+----------+
上表没有主键, 所以可能会出现重复的行。
每行可以是一个帖子或对该帖子的评论。
如果是帖子的话,parent_id 就是 null。
对于评论来说,parent_id 就是表中对应帖子的 sub_id。

编写 SQL 语句以查找每个帖子的评论数。
结果表应包含帖子的 post_id 和对应的评论数 number_of_comments 并且按 post_id 升序排列。
Submissions 可能包含重复的评论。您应该计算每个帖子的唯一评论数。
Submissions 可能包含重复的帖子。您应该将它们视为一个帖子。

查询结果格式如下例所示:

Submissions table:
+---------+------------+
| sub_id  | parent_id  |
+---------+------------+
| 1       | Null       |
| 2       | Null       |
| 1       | Null       |
| 12      | Null       |
| 3       | 1          |
| 5       | 2          |
| 3       | 1          |
| 4       | 1          |
| 9       | 1          |
| 10      | 2          |
| 6       | 7          |
+---------+------------+

结果表:
+---------+--------------------+
| post_id | number_of_comments |
+---------+--------------------+
| 1       | 3                  |
| 2       | 2                  |
| 12      | 0                  |
+---------+--------------------+

表中 ID 为 1 的帖子有 ID 为 349 的三个评论。表中 ID 为 3 的评论重复出现了,所以我们只对它进行了一次计数。
表中 ID 为 2 的帖子有 ID 为 510 的两个评论。
ID 为 12 的帖子在表中没有评论。
表中 ID 为 6 的评论是对 ID 为 7 的已删除帖子的评论,因此我们将其忽略。
  • SQL1:

    • select
      t1.post_id, ifnull(t2.cnt, 0) number_of_comments
      from
          (select
          distinct sub_id post_id
          from
          Submissions
          where parent_id is null
          order by post_id) t1
          left join
          (select
          distinct parent_id,
          count(parent_id) over(partition by parent_id order by parent_id) cnt
          from
              (select
              distinct sub_id, parent_id
              from
              Submissions) t) t2
      on t1.post_id = t2.parent_id
      
  • SQL2:

    • select
      post_id, count(sub_id) number_of_comments
      from
          (select
          distinct t1.sub_id post_id, t2.sub_id sub_id
          from
          Submissions t1 left join Submissions t2
          on t1.sub_id = t2.parent_id
          where t1.parent_id is null
      ) t
      group by t.post_id
      order by t.post_id
      
  • SQL3:

    • select
      post_id,
      count(distinct t2.sub_id) number_of_comments
      from
          (select
          distinct sub_id post_id
          from
          Submissions
          where parent_id is null) t1
          left join Submissions t2
          on t1.post_id = t2.parent_id
      group by t1.post_id
      order by t1.post_id
      

平均售价

Table: Prices

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| product_id    | int     |
| start_date    | date    |
| end_date      | date    |
| price         | int     |
+---------------+---------+
(product_id,start_date,end_date) 是 Prices 表的主键。
Prices 表的每一行表示的是某个产品在一段时期内的价格。
每个产品的对应时间段是不会重叠的,这也意味着同一个产品的价格时段不会出现交叉。

Table: UnitsSold

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| product_id    | int     |
| purchase_date | date    |
| units         | int     |
+---------------+---------+
UnitsSold 表没有主键,它可能包含重复项。
UnitsSold 表的每一行表示的是每种产品的出售日期,单位和产品 id。

编写SQL查询以查找每种产品的平均售价。
average_price 应该四舍五入到小数点后两位。

查询结果格式如下例所示:

Prices table:
+------------+------------+------------+--------+
| product_id | start_date | end_date   | price  |
+------------+------------+------------+--------+
| 1          | 2019-02-17 | 2019-02-28 | 5      |
| 1          | 2019-03-01 | 2019-03-22 | 20     |
| 2          | 2019-02-01 | 2019-02-20 | 15     |
| 2          | 2019-02-21 | 2019-03-31 | 30     |
+------------+------------+------------+--------+
 
UnitsSold table:
+------------+---------------+-------+
| product_id | purchase_date | units |
+------------+---------------+-------+
| 1          | 2019-02-25    | 100   |
| 1          | 2019-03-01    | 15    |
| 2          | 2019-02-10    | 200   |
| 2          | 2019-03-22    | 30    |
+------------+---------------+-------+

Result table:
+------------+---------------+
| product_id | average_price |
+------------+---------------+
| 1          | 6.96          |
| 2          | 16.96         |
+------------+---------------+
平均售价 = 产品总价 / 销售的产品数量。
产品 1 的平均售价 = ((100 * 5)+(15 * 20) )/ 115 = 6.96
产品 2 的平均售价 = ((200 * 15)+(30 * 30) )/ 230 = 16.96
  • 这里不需要去重

  • SQL:

    • select
      t.product_id, round(sum(t.sum) / sum(units), 2) average_price
      from
      (select
      p.product_id, p.price * u.units sum, u.units
      from
      Prices p join UnitsSold u
      on p.product_id = u.product_id
      where u.purchase_date between p.start_date and p.end_date) t
      group by t.product_id
      

页面推荐

朋友关系列表: Friendship

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| user1_id      | int     |
| user2_id      | int     |
+---------------+---------+
这张表的主键是 (user1_id, user2_id)。
这张表的每一行代表着 user1_id 和 user2_id 之间存在着朋友关系。

 

喜欢列表: Likes

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| user_id     | int     |
| page_id     | int     |
+-------------+---------+
这张表的主键是 (user_id, page_id)。
这张表的每一行代表着 user_id 喜欢 page_id。

写一段 SQL  向user_id = 1 的用户,推荐其朋友们喜欢的页面。不要推荐该用户已经喜欢的页面。
你返回的结果中不应当包含重复项。

返回结果的格式如下例所示:

Friendship table:
+----------+----------+
| user1_id | user2_id |
+----------+----------+
| 1        | 2        |
| 1        | 3        |
| 1        | 4        |
| 2        | 3        |
| 2        | 4        |
| 2        | 5        |
| 6        | 1        |
+----------+----------+
 
Likes table:
+---------+---------+
| user_id | page_id |
+---------+---------+
| 1       | 88      |
| 2       | 23      |
| 3       | 24      |
| 4       | 56      |
| 5       | 11      |
| 6       | 33      |
| 2       | 77      |
| 3       | 77      |
| 6       | 88      |
+---------+---------+

Result table:
+------------------+
| recommended_page |
+------------------+
| 23               |
| 24               |
| 56               |
| 33               |
| 77               |
+------------------+
用户1 同 用户2, 3, 4, 6 是朋友关系。
推荐页面为: 页面23 来自于 用户2, 页面24 来自于 用户3, 页面56 来自于 用户3 以及 页面33 来自于 用户6。
页面77 同时被 用户2 和 用户3 推荐。
页面88 没有被推荐,因为 用户1 已经喜欢了它。
  • SQL1:

    • select
      t.recommended_page
      from
          (select
          distinct t2.page_id recommended_page
          from
              (select
              user2_id
              from
              Friendship
              where user1_id = '1') t1
          join Likes t2
          on t1.user2_id = t2.user_id
          union all
          select
          distinct t2.page_id recommended_page
          from
              (select
              user1_id
              from
              Friendship
              where user2_id = '1') t1
          join Likes t2
          on t1.user1_id = t2.user_id) t
      where recommended_page not in (select
                                    page_id
                                    from
                                    Likes
                                    where user_id = '1')
      
  • SQL2:

    • select
      distinct page_id recommended_page
      from
      Likes
      where user_id in (select
                        user1_id user_id
                        from
                        Friendship
                        where user2_id = '1'
                        union all
                        select
                        user2_id user_id
                        from
                        Friendship
                        where user1_id = '1')
            AND page_id not in (select
                                page_id
                                from
                                Likes
                                where user_id = '1')
      

向公司CEO汇报工作的所有人

员工表:Employees

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| employee_id   | int     |
| employee_name | varchar |
| manager_id    | int     |
+---------------+---------+
employee_id 是这个表的主键。
这个表中每一行中,employee_id 表示职工的 ID,employee_name 表示职工的名字,manager_id 表示该职工汇报工作的直线经理。
这个公司 CEO 是 employee_id = 1 的人。

用 SQL 查询出所有直接或间接向公司 CEO 汇报工作的职工的 employee_id 。
由于公司规模较小,经理之间的间接关系不超过 3 个经理。
可以以任何顺序返回的结果,不需要去重。

查询结果示例如下:

Employees table:
+-------------+---------------+------------+
| employee_id | employee_name | manager_id |
+-------------+---------------+------------+
| 1           | Boss          | 1          |
| 3           | Alice         | 3          |
| 2           | Bob           | 1          |
| 4           | Daniel        | 2          |
| 7           | Luis          | 4          |
| 8           | Jhon          | 3          |
| 9           | Angela        | 8          |
| 77          | Robert        | 1          |
+-------------+---------------+------------+

Result table:
+-------------+
| employee_id |
+-------------+
| 2           |
| 77          |
| 4           |
| 7           |
+-------------+

公司 CEO 的 employee_id 是 1.
employee_id 是 277 的职员直接汇报给公司 CEO。
employee_id 是 4 的职员间接汇报给公司 CEO 4 --> 2 --> 1 。
employee_id 是 7 的职员间接汇报给公司 CEO 7 --> 4 --> 2 --> 1 。
employee_id 是 3, 89 的职员不会直接或间接的汇报给公司 CEO。 
  • SQL:
    • 1 <-- e3 <-- e2 <-- e1
    • select
      e1.employee_id
      from
      Employees e1 join Employees e2
      on e1.manager_id = e2.employee_id
      join Employees e3
      on e2.manager_id = e3.employee_id
      where e1.employee_id != 1 and e3.manager_id = 1
      

学生们参加各科测试的次数

学生表: Students

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| student_id    | int     |
| student_name  | varchar |
+---------------+---------+
主键为 student_id(学生ID),该表内的每一行都记录有学校一名学生的信息。

科目表: Subjects

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| subject_name | varchar |
+--------------+---------+
主键为 subject_name(科目名称),每一行记录学校的一门科目名称。

考试表: Examinations

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| student_id   | int     |
| subject_name | varchar |
+--------------+---------+
这张表压根没有主键,可能会有重复行。
学生表里的一个学生修读科目表里的每一门科目,而这张考试表的每一行记录就表示学生表里的某个学生参加了一次科目表里某门科目的测试。

要求写一段 SQL 语句,查询出每个学生参加每一门科目测试的次数,结果按 student_id 和 subject_name 排序。

查询结构格式如下所示:

Students table:
+------------+--------------+
| student_id | student_name |
+------------+--------------+
| 1          | Alice        |
| 2          | Bob          |
| 13         | John         |
| 6          | Alex         |
+------------+--------------+
Subjects table:
+--------------+
| subject_name |
+--------------+
| Math         |
| Physics      |
| Programming  |
+--------------+
Examinations table:
+------------+--------------+
| student_id | subject_name |
+------------+--------------+
| 1          | Math         |
| 1          | Physics      |
| 1          | Programming  |
| 2          | Programming  |
| 1          | Physics      |
| 1          | Math         |
| 13         | Math         |
| 13         | Programming  |
| 13         | Physics      |
| 2          | Math         |
| 1          | Math         |
+------------+--------------+
Result table:
+------------+--------------+--------------+----------------+
| student_id | student_name | subject_name | attended_exams |
+------------+--------------+--------------+----------------+
| 1          | Alice        | Math         | 3              |
| 1          | Alice        | Physics      | 2              |
| 1          | Alice        | Programming  | 1              |
| 2          | Bob          | Math         | 1              |
| 2          | Bob          | Physics      | 0              |
| 2          | Bob          | Programming  | 1              |
| 6          | Alex         | Math         | 0              |
| 6          | Alex         | Physics      | 0              |
| 6          | Alex         | Programming  | 0              |
| 13         | John         | Math         | 1              |
| 13         | John         | Physics      | 1              |
| 13         | John         | Programming  | 1              |
+------------+--------------+--------------+----------------+
结果表需包含所有学生和所有科目(即便测试次数为0):
Alice 参加了 3 次数学测试, 2 次物理测试,以及 1 次编程测试;
Bob 参加了 1 次数学测试, 1 次编程测试,没有参加物理测试;
Alex 啥测试都没参加;
John  参加了数学、物理、编程测试各 1 次。
  • cross join

    • 交叉连接,笛卡尔积
    • 不需要on或者using关键字,返回行数:A表 x B表
  • COUNT()

    • COUNT(*):不忽略NULL值
    • COUNT(字段名):忽略NULL值
  • SQL:

    • select
      s1.student_id, s1.student_name, s2.subject_name, count(e.subject_name) attended_exams
      from
      Students s1 cross join Subjects s2 left join Examinations e
      on s1.student_id = e.student_id and s2.subject_name = e.subject_name
      group by s1.student_id, s2.subject_name
      order by s1.student_id, s2.subject_name
      

找到连续区间的开始和结束数字

表:Logs

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| log_id        | int     |
+---------------+---------+
id 是上表的主键。
上表的每一行包含日志表中的一个 ID。

后来一些 ID 从 Logs 表中删除。编写一个 SQL 查询得到 Logs 表中的连续区间的开始数字和结束数字。
将查询表按照 start_id 排序。

查询结果格式如下面的例子:

Logs 表:
+------------+
| log_id     |
+------------+
| 1          |
| 2          |
| 3          |
| 7          |
| 8          |
| 10         |
+------------+

结果表:
+------------+--------------+
| start_id   | end_id       |
+------------+--------------+
| 1          | 3            |
| 7          | 8            |
| 10         | 10           |
+------------+--------------+
结果表应包含 Logs 表中的所有区间。
从 1 到 3 在表中。
从 4 到 6 不在表中。
从 7 到 8 在表中。
9 不在表中。
10 在表中。
  • SQL1:

    • 自连接
    • select
      a.log_id start_id, min(b.log_id) end_id
      from
        (select
        log_id
        from
        Logs
        where log_id - 1 not in (select * from Logs)) a,
        (select
        log_id
        from
        Logs
        where log_id + 1 not in (select * from Logs)) b
      where b.log_id >= a.log_id
      group by a.log_id
      
  • SQL2:

    • 窗口函数
    • select
      min(t.log_id) start_id, max(t.log_id) end_id
      from
          (select
          log_id,
          log_id - ROW_NUMBER() over() a
          from
          Logs) t
      group by t.a
      

不同国家的天气类型

国家表:Countries

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| country_id    | int     |
| country_name  | varchar |
+---------------+---------+
country_id 是这张表的主键。
该表的每行有 country_id 和 country_name 两列。

天气表:Weather

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| country_id    | int     |
| weather_state | varchar |
| day           | date    |
+---------------+---------+
(country_id, day) 是该表的复合主键。
该表的每一行记录了某个国家某一天的天气情况。

天气类型的定义如下:当 weather_state 的平均值小于或等于15返回 Cold,当 weather_state 的平均值大于或等于 25 返回 Hot,否则返回 Warm
写一段 SQL 来找到表中每个国家在 2019 年 11 月的天气类型。
你可以以任意顺序返回你的查询结果。

查询结果格式如下所示:

Countries table:
+------------+--------------+
| country_id | country_name |
+------------+--------------+
| 2          | USA          |
| 3          | Australia    |
| 7          | Peru         |
| 5          | China        |
| 8          | Morocco      |
| 9          | Spain        |
+------------+--------------+
Weather table:
+------------+---------------+------------+
| country_id | weather_state | day        |
+------------+---------------+------------+
| 2          | 15            | 2019-11-01 |
| 2          | 12            | 2019-10-28 |
| 2          | 12            | 2019-10-27 |
| 3          | -2            | 2019-11-10 |
| 3          | 0             | 2019-11-11 |
| 3          | 3             | 2019-11-12 |
| 5          | 16            | 2019-11-07 |
| 5          | 18            | 2019-11-09 |
| 5          | 21            | 2019-11-23 |
| 7          | 25            | 2019-11-28 |
| 7          | 22            | 2019-12-01 |
| 7          | 20            | 2019-12-02 |
| 8          | 25            | 2019-11-05 |
| 8          | 27            | 2019-11-15 |
| 8          | 31            | 2019-11-25 |
| 9          | 7             | 2019-10-23 |
| 9          | 3             | 2019-12-23 |
+------------+---------------+------------+
Result table:
+--------------+--------------+
| country_name | weather_type |
+--------------+--------------+
| USA          | Cold         |
| Austraila    | Cold         |
| Peru         | Hot          |
| China        | Warm         |
| Morocco      | Hot          |
+--------------+--------------+
USA 11 月的平均 weather_state  (15) / 1 = 15 所以天气类型为 Cold。
Australia 11 月的平均 weather_state  (-2 + 0 + 3) / 3 = 0.333 所以天气类型为 Cold。
Peru 11 月的平均 weather_state  (25) / 1 = 25 所以天气类型为 Hot。
China 11 月的平均 weather_state  (16 + 18 + 21) / 3 = 18.333 所以天气类型为 Warm。
Morocco 11 月的平均 weather_state  (25 + 27 + 31) / 3 = 27.667 所以天气类型为 Hot。
我们并不知道 Spain  11 月的 weather_state 情况所以无需将他包含在结果中。
  • 判断月份:

    • YEAR(day) = 2019 AND MONTH(day) = 11
    • day BETWEEN '2019-11-01' AND '2019-11-30'
    • date_format(day, '%Y-%m') = '2019-11'
    • LEFT(order_date, 7) = '2019-11'
  • SQL:

    • select
      t.country_name,
      if(t.avg <= 15, 'Cold', if(t.avg >= 25, 'Hot', 'Warm')) weather_type
      from
          (select
          c.country_name, avg(w.weather_state) avg, date_format(w.day, '%Y-%m') m
          from
          Countries c join Weather w
          on c.country_id = w.country_id
          group by c.country_id, m
          having m = '2019-11') t
      

求团队人数

员工表:Employee

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| employee_id   | int     |
| team_id       | int     |
+---------------+---------+
employee_id 字段是这张表的主键,表中的每一行都包含每个员工的 ID 和他们所属的团队。

编写一个 SQL 查询,以求得每个员工所在团队的总人数。
查询结果中的顺序无特定要求。

查询结果格式示例如下:

Employee Table:
+-------------+------------+
| employee_id | team_id    |
+-------------+------------+
|     1       |     8      |
|     2       |     8      |
|     3       |     8      |
|     4       |     7      |
|     5       |     9      |
|     6       |     9      |
+-------------+------------+
Result table:
+-------------+------------+
| employee_id | team_size  |
+-------------+------------+
|     1       |     3      |
|     2       |     3      |
|     3       |     3      |
|     4       |     1      |
|     5       |     2      |
|     6       |     2      |
+-------------+------------+
ID 为 123 的员工是 team_id 为 8 的团队的成员,
ID 为 4 的员工是 team_id 为 7 的团队的成员,
ID 为 56 的员工是 team_id 为 9 的团队的成员。
  • SQL1:

    • 自连接
    • select
      e1.employee_id, count(*) team_size
      from
      Employee e1 join Employee e2 using(team_id)
      group by e1.employee_id
      
  • SQL2:

    • 子查询
    • select
      employee_id,
      (select
      count(*)
      from
      Employee e2
      where e1.team_id = e2.team_id
      ) team_size
      from Employee e1
      
  • SQL3:

    • 窗口函数
    • select
      employee_id, count(team_id) over(partition by team_id) team_size
      from
      Employee
      

不同性别每日分数总计

表: Scores

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| player_name   | varchar |
| gender        | varchar |
| day           | date    |
| score_points  | int     |
+---------------+---------+
(gender, day)是该表的主键
一场比赛是在女队和男队之间举行的
该表的每一行表示一个名叫 (player_name) 性别为 (gender) 的参赛者在某一天获得了 (score_points) 的分数
如果参赛者是女性,那么 gender 列为 'F',如果参赛者是男性,那么 gender 列为 'M'

写一条SQL语句查询每种性别在每一天的总分,并按性别和日期对查询结果排序。

下面是查询结果格式的例子:

Scores表:
+-------------+--------+------------+--------------+
| player_name | gender | day        | score_points |
+-------------+--------+------------+--------------+
| Aron        | F      | 2020-01-01 | 17           |
| Alice       | F      | 2020-01-07 | 23           |
| Bajrang     | M      | 2020-01-07 | 7            |
| Khali       | M      | 2019-12-25 | 11           |
| Slaman      | M      | 2019-12-30 | 13           |
| Joe         | M      | 2019-12-31 | 3            |
| Jose        | M      | 2019-12-18 | 2            |
| Priya       | F      | 2019-12-31 | 23           |
| Priyanka    | F      | 2019-12-30 | 17           |
+-------------+--------+------------+--------------+
结果表:
+--------+------------+-------+
| gender | day        | total |
+--------+------------+-------+
| F      | 2019-12-30 | 17    |
| F      | 2019-12-31 | 40    |
| F      | 2020-01-01 | 57    |
| F      | 2020-01-07 | 80    |
| M      | 2019-12-18 | 2     |
| M      | 2019-12-25 | 13    |
| M      | 2019-12-30 | 26    |
| M      | 2019-12-31 | 29    |
| M      | 2020-01-07 | 36    |
+--------+------------+-------+
女性队伍:
第一天是 2019-12-30,Priyanka 获得 17 分,队伍的总分是 17 
第二天是 2019-12-31, Priya 获得 23 分,队伍的总分是 40 
第三天是 2020-01-01, Aron 获得 17 分,队伍的总分是 57 
第四天是 2020-01-07, Alice 获得 23 分,队伍的总分是 80 
男性队伍:
第一天是 2019-12-18, Jose 获得 2 分,队伍的总分是 2 
第二天是 2019-12-25, Khali 获得 11 分,队伍的总分是 13 
第三天是 2019-12-30, Slaman 获得 13 分,队伍的总分是 26 
第四天是 2019-12-31, Joe 获得 3 分,队伍的总分是 29 
第五天是 2020-01-07, Bajrang 获得 7 分,队伍的总分是 36 
  • SQL1:

    • 自连接
    • select
      s1.gender, s1.day, sum(s2.score_points) total
      from
      Scores s1 join Scores s2
      on s1.gender = s2.gender and s1.day >= s2.day
      group by s1.gender, s1.day
      order by s1.gender, s1.day
      
  • SQL2:

    • select
      gender, day,
      sum(score_points) over(partition by gender order by day) total
      from
      Scores
      order by gender, day
      

餐馆营业额变化增长

表: Customer

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| customer_id   | int     |
| name          | varchar |
| visited_on    | date    |
| amount        | int     |
+---------------+---------+
(customer_id, visited_on) 是该表的主键
该表包含一家餐馆的顾客交易数据
visited_on 表示 (customer_id) 的顾客在 visited_on 那天访问了餐馆
amount 是一个顾客某一天的消费总额

你是餐馆的老板,现在你想分析一下可能的营业额变化增长(每天至少有一位顾客)。
写一条 SQL 查询计算以 7 天(某日期 + 该日期前的 6 天)为一个时间段的顾客消费平均值。

查询结果格式的例子如下:

  • 查询结果按 visited_on 排序
  • average_amount 要 保留两位小数,日期数据的格式为 ('YYYY-MM-DD')
Customer 表:
+-------------+--------------+--------------+-------------+
| customer_id | name         | visited_on   | amount      |
+-------------+--------------+--------------+-------------+
| 1           | Jhon         | 2019-01-01   | 100         |
| 2           | Daniel       | 2019-01-02   | 110         |
| 3           | Jade         | 2019-01-03   | 120         |
| 4           | Khaled       | 2019-01-04   | 130         |
| 5           | Winston      | 2019-01-05   | 110         | 
| 6           | Elvis        | 2019-01-06   | 140         | 
| 7           | Anna         | 2019-01-07   | 150         |
| 8           | Maria        | 2019-01-08   | 80          |
| 9           | Jaze         | 2019-01-09   | 110         | 
| 1           | Jhon         | 2019-01-10   | 130         | 
| 3           | Jade         | 2019-01-10   | 150         | 
+-------------+--------------+--------------+-------------+

结果表:
+--------------+--------------+----------------+
| visited_on   | amount       | average_amount |
+--------------+--------------+----------------+
| 2019-01-07   | 860          | 122.86         |
| 2019-01-08   | 840          | 120            |
| 2019-01-09   | 840          | 120            |
| 2019-01-10   | 1000         | 142.86         |
+--------------+--------------+----------------+

第一个七天消费平均值从 2019-01-01  2019-01-07  (100 + 110 + 120 + 130 + 110 + 140 + 150)/7 = 122.86
第二个七天消费平均值从 2019-01-02  2019-01-08  (110 + 120 + 130 + 110 + 140 + 150 + 80)/7 = 120
第三个七天消费平均值从 2019-01-03  2019-01-09  (120 + 130 + 110 + 140 + 150 + 80 + 110)/7 = 120
第四个七天消费平均值从 2019-01-04  2019-01-10  (130 + 110 + 140 + 150 + 80 + 110 + 130 + 150)/7 = 142.86
  • SQL1:

    • 自连接
    • select
      t1.visited_on,
      sum(t2.amount) as amount,
      round(avg(t2.amount), 2) average_amount
      from
          (select
          visited_on, sum(amount) amount
          from
          Customer
          group by visited_on) t1,
          (select
          visited_on, sum(amount) amount
          from
          Customer
          group by visited_on) t2
      where datediff(t1.visited_on, t2.visited_on) <= 6 and
            datediff(t1.visited_on, t2.visited_on) >= 0 and
            datediff(t1.visited_on, (select min(visited_on) from customer)) >= 6
      group by t1.visited_on
      
  • 窗口函数

  • SQL2:

    • 从第7条记录开始向后取
    • select
      distinct visited_on,
      sum(amount) over(ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) amount,
      round(avg(amount) over(ROWS BETWEEN 6 PRECEDING AND CURRENT ROW), 2) average_amount
      from
          (select
          distinct visited_on,
          sum(amount) over(partition by visited_on order by visited_on) amount
          from
          Customer) t
      limit 6, 18446744073709551615
      
  • SQL3:

    • 通过编号获取
    • select
      visited_on, amount, average_amount
      from
          (select
          visited_on,
          sum(amount) over(order by visited_on ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) amount,
          round(avg(amount) over(ROWS BETWEEN 6 PRECEDING AND CURRENT ROW), 2) average_amount,
          ROW_NUMBER() OVER(order by visited_on) rn
          from
              (select
              distinct visited_on,
              sum(amount) over(partition by visited_on order by visited_on) amount
              from
              Customer) t
          ) t1
      where t1.rn >= 7