SQL(四)

目录

SQL子查询和临时表格

子查询

子查询(第一部分)

子查询(第二部分)

练习题目

with

练习题目

 


子查询

子查询(第一部分)

我们想要计算每个渠道每天的平均事件次数。

第一个表格将提供每个渠道每天的事件次数,然后我们将使用第二个查询对这些值求平均。

/*
select DATE_TRUNC('day',occurred_at) as day,
channel,
count(*) event_count
from web_events
group by 1,2
order by event_count DESC;

select *
from
(select DATE_TRUNC('day',occurred_at) as day,
channel,
count(*) event_count
from web_events
group by 1,2
order by event_count DESC) sub
*/

select channel,
avg(event_count) avg_event_counts
from
(select DATE_TRUNC('day',occurred_at) as day,
channel,
count(*) event_count
from web_events
group by 1,2 
) sub
group by channel;

子查询格式

在编写子查询时,查询很容易就看起来很复杂。为了便于阅读:

要记住的重要事项是,在使用子查询时,要让读者能够轻松地判断查询的哪个部分将一起执行。大部分人的做法是按照某种方式缩进子查询,

SELECT *
FROM (SELECT DATE_TRUNC('day',occurred_at) AS day,
                channel, COUNT(*) as events
      FROM web_events 
      GROUP BY 1,2
      ORDER BY 3 DESC) sub
GROUP BY channel
ORDER BY 2 DESC;

子查询(第二部分)

在上面的子查询中,你编写了一个子查询来创建表格,然后可以在 FROM 语句中查询该表格。但是,如果只返回一个值,则可以在逻辑语句中使用该值,例如 WHEREHAVING,甚至 SELECT,该值可以嵌套在 CASE 语句中。

标量子查询的书写位置并不仅仅局限于 WHERE 子句中,通常任何可以使用单一值的位置都可以使用。也就是说, 能够使用常数或者列名的地方,无论是 SELECT 子句、 GROUP BY 子句、 HAVING 子句,还是ORDER BY 子句,几乎所有的地方都可以使用。

注意:在条件语句中编写子查询时,不能包含别名。这是因为该子查询会被当做单个值(或者对于 IN 情况是一组值),而不是一个表格。同时注意,这里的查询对应的是单个值。如果我们返回了整个列,则需要使用 IN 来执行逻辑参数。如果我们要返回整个表格,则必须为该表格使用别名,并对整个表格执行其他逻辑。

/*
SELECT DATE_TRUNC('month', MIN(occurred_at))
FROM orders;
*/
      
SELECT AVG(standard_qty) avg_std, AVG(gloss_qty) avg_gls, AVG(poster_qty) avg_pst
FROM orders
WHERE DATE_TRUNC('month', occurred_at) =
(SELECT DATE_TRUNC('month', MIN(occurred_at)) FROM orders);

SELECT SUM(total_amt_usd)
FROM orders
WHERE DATE_TRUNC('month', occurred_at) =
(SELECT DATE_TRUNC('month', MIN(occurred_at)) FROM orders);

练习题目

以下是数据库的 ERD,当你处理下面的练习时,可能会用到该 ERD。

练习1:提供每个区域拥有最高销售额 (total_amt_usd) 的销售代表姓名

#每个销售代表在每个区域总的销售额
SELECT s.name rep_name, r.name region_name, SUM(o.total_amt_usd) total_amt
FROM sales_reps s
JOIN accounts a
ON a.sales_rep_id = s.id
JOIN orders o
ON o.account_id = a.id
JOIN region r
ON r.id = s.region_id
GROUP BY 1,2
ORDER BY 3 DESC;

#每个区域的最大销售额
SELECT region_name, MAX(total_amt) total_amt
FROM(SELECT s.name rep_name, r.name region_name, SUM(o.total_amt_usd) total_amt
FROM sales_reps s
JOIN accounts a
ON a.sales_rep_id = s.id
JOIN orders o
ON o.account_id = a.id
JOIN region r
ON r.id = s.region_id
GROUP BY 1, 2) inner1
GROUP BY 1;

#将得到的两个表进行联结,得到最终结果
SELECT t1.rep_name, t1.region_name, t1.total_amt
FROM(SELECT s.name rep_name, r.name region_name, SUM(o.total_amt_usd) total_amt
FROM sales_reps s
JOIN accounts a
ON a.sales_rep_id = s.id
JOIN orders o
ON o.account_id = a.id
JOIN region r
ON r.id = s.region_id
GROUP BY 1,2
ORDER BY 3 DESC) t1
JOIN (SELECT region_name, MAX(total_amt) total_amt
FROM(SELECT s.name rep_name, r.name region_name, SUM(o.total_amt_usd) total_amt
FROM sales_reps s
JOIN accounts a
ON a.sales_rep_id = s.id
JOIN orders o
ON o.account_id = a.id
JOIN region r
ON r.id = s.region_id
GROUP BY 1, 2) inner1
GROUP BY 1) t2
ON t1.region_name = t2.region_name
AND t1.total_amt = t2.total_amt;

练习2:对于具有最高销售额 (total_amt_usd) 的区域,总共下了多少个订单 (total count orders) ?

#先获得最高销售额 (total_amt_usd) 的区域名称
select r.name
from region r
join sales_reps s
on s.region_id = r.id
join accounts a                
on a.sales_rep_id = s.id                
join orders o                
on o.account_id = a.id                
group by r.name                
order by sum(o.total_amt_usd) DESC                
limit 1

#利用标量子查询得到所需结果
select r.name,sum(total) total_counts
from region r
join sales_reps s
on s.region_id = r.id
join accounts a
on a.sales_rep_id = s.id
join orders o
on o.account_id = a.id
where r.name = (select r.name
                from region r 
                join sales_reps s
                on s.region_id = r.id
                join accounts a
                on a.sales_rep_id = s.id
                join orders o
                on o.account_id = a.id
                group by r.name
                order by sum(o.total_amt_usd) DESC
                limit 1)
group by r.name;

练习3:有多少客户的购买总数(total)比购买标准纸张数量 (standard_qty) 最多的客户(在作为客户的整个时期内)的购买总数(total)还多?

select a.name account_name,sum(o.standard_qty) total_std, sum(o.total) total
from accounts a
join orders o
on o.account_id = a.id
group by a.name
order by 2 DESC
limit 1;

SELECT a.name
FROM orders o
JOIN accounts a
ON a.id = o.account_id
GROUP BY 1
HAVING SUM(o.total) > (SELECT total
FROM (SELECT a.name act_name, SUM(o.standard_qty) tot_std, SUM(o.total) total
FROM accounts a
JOIN orders o
ON o.account_id = a.id
GROUP BY 1
ORDER BY 2 DESC
LIMIT 1) sub);

练习4:对于总消费前十名的客户,他们的平均终身消费 (total_amt_usd) 是多少?

SELECT AVG(tot_spent)
FROM (SELECT a.id, a.name, SUM(o.total_amt_usd) tot_spent
FROM orders o
JOIN accounts a
ON a.id = o.account_id
GROUP BY a.id, a.name
ORDER BY 3 DESC
LIMIT 10) temp;

with

WITH 语句经常称为公用表表达式(简称 CTE)。虽然这些表达式和子查询的目的完全一样,但是实际更常用,因为更容易看懂其中的逻辑。

练习题目

练习之前的题目

练习1:提供每个区域拥有最高销售额 (total_amt_usd) 的销售代表姓名

WITH t1 AS (
SELECT s.name rep_name, r.name region_name, SUM(o.total_amt_usd) total_amt
FROM sales_reps s
JOIN accounts a
ON a.sales_rep_id = s.id
JOIN orders o
ON o.account_id = a.id
JOIN region r
ON r.id = s.region_id
GROUP BY 1,2
ORDER BY 3 DESC),
t2 AS (
SELECT region_name, MAX(total_amt) total_amt
FROM t1
GROUP BY 1)
SELECT t1.rep_name, t1.region_name, t1.total_amt
FROM t1
JOIN t2
ON t1.region_name = t2.region_name AND t1.total_amt = t2.total_amt;

练习2:对于具有最高销售额 (total_amt_usd) 的区域,总共下了多少个订单 (total count orders) ?

WITH t1 AS (
SELECT r.name region_name, SUM(o.total_amt_usd) total_amt
FROM sales_reps s
JOIN accounts a
ON a.sales_rep_id = s.id
JOIN orders o
ON o.account_id = a.id
JOIN region r
ON r.id = s.region_id
GROUP BY r.name),
t2 AS (
SELECT MAX(total_amt)
FROM t1)
SELECT r.name, SUM(o.total) total_orders
FROM sales_reps s
JOIN accounts a
ON a.sales_rep_id = s.id
JOIN orders o
ON o.account_id = a.id
JOIN region r
ON r.id = s.region_id
GROUP BY r.name
HAVING SUM(o.total_amt_usd) = (SELECT * FROM t2);

练习3:有多少客户的购买总数(total)比购买标准纸张数量 (standard_qty) 最多的客户(在作为客户的整个时期内)的购买总数(total)还多?

WITH t1 AS (
SELECT a.name account_name, SUM(o.standard_qty) total_std, SUM(o.total) total
FROM accounts a
JOIN orders o
ON o.account_id = a.id
GROUP BY 1
ORDER BY 2 DESC
LIMIT 1),
t2 AS (
SELECT a.name
FROM orders o
JOIN accounts a
ON a.id = o.account_id
GROUP BY 1
HAVING SUM(o.total) > (SELECT total FROM t1))
SELECT COUNT(*)
FROM t2;

练习4:对于总消费前十名的客户,他们的平均终身消费 (total_amt_usd) 是多少?

WITH t1 AS (
SELECT a.id, a.name, SUM(o.total_amt_usd) tot_spent
FROM orders o
JOIN accounts a
ON a.id = o.account_id
GROUP BY a.id, a.name
ORDER BY 3 DESC
LIMIT 10)
SELECT AVG(tot_spent)
FROM t1;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值