【SQL边干边学系列】08高级问题-4

文章目录

  • 前言
  • 回顾
  • 高级问题
    • 48.客户分组
    • 49.客户分组-修复null
    • 50.使用百分比的客户分组
    • 51.灵活的客户分组
  • 答案
    • 48.客户分组
    • 49.客户分组-修复null
    • 50.使用百分比的客户分组
    • 51.灵活的客户分组
  • 未完待续


前言

在这里插入图片描述
该系列教程,将会从实际问题出发,边干边学,逐步深入讲解SQL的各方面知识。

你需要完成所有的问题吗?绝对不是。介绍性的问题相当简单,所以你可以直接跳过到“中级问题”部分。如果你不是初学者,但不确定应该从哪里开始,请在“入门问题”部分看看问题和预期结果,并确保你理解这些概念。如果已经理解了这些概念,请开始阅读“中级问题”部分。

你想从这本书中复制代码并在你的服务器上运行?我建议你手动输入,而不是复制粘贴。为什么要去麻烦地重新打字呢?科学表明,打字的行为会在你的脑中留下更深刻的印象。当你只是复制和粘贴时,代码只是直接从你电脑里的一个窗口转到另一个窗口,而不会给你留下多少印象。但是当你把它打出来时,你必须集中精力,这非常有助于保留信息。

一旦你完成了所有的问题,将拥有一些在数据分析和高级Select语句使用方面非常有用的技能。当然,这并不是SQL的全部内容。还有修改数据(更新、插入、删除)、DDL(数据定义语言,即如何创建和修改数据库对象)、编程(如存储过程)和许多其他主题。

该系列教程中,只涉及到了使用Select语句检索数据的问题,这几乎是所有其他数据库主题的基础开端。


回顾

上篇文章👉《【SQL边干边学系列】07高级问题-3》 讲了部分高级问题,这篇接着讨论更多的高级问题。


高级问题

48.客户分组

假如想为现有客户做一个销售活动。希望想根据客户在2016年的订购量,将他们分组。然后,根据客户所在的群组,采用不同的销售材料。

客户分组类别为0到1000、1000到5000、5000到10000个,以及超过10000个。

这个查询的一个很好的起点是来自“高价值客户-总订单”这个问题的答案。我们不想展示2016年没有任何订单的客户。

按CustomerID对结果排序。

-- 预期结果
CustomerID CompanyName                        TotalOrderAmount CustomerGroup
---------- ---------------------------------- ---------------- -------------
ALFKI      Alfreds Futterkiste                2302.20          Medium
ANATR      Ana Trujillo Emparedados y helados 514.40           Low
ANTON      Antonio Moreno Taquería            660.00           Low
...
WHITC White Clover Markets 15278.90 Very High
WILMK Wilman Kala 1987.00 Medium
WOLZA Wolski Zajazd 1865.10 Medium
(81 row(s) affected)

提示如下

这是来自“高价值客户-总订单”问题的SQL,但没有针对订单总数超过10,000个的过滤器。

SelectCustomers.CustomerID,Customers.CompanyName,TotalOrderAmount = SUM(Quantity * UnitPrice)
From CustomersJoin Orderson Orders.CustomerID = Customers.CustomerIDJoin OrderDetailson Orders.OrderID = OrderDetails.OrderID
WhereOrderDate >= '20160101'and OrderDate < '20170101'
Group ByCustomers.CustomerID,Customers.CompanyName
Order By TotalOrderAmount Desc;

你可以在CTE(common table expression)中使用上面的SQL,然后在“TotalOrderAmount”上使用Case语句。

49.客户分组-修复null

上一个问题的答案有一个错误。CustomerGroup中有一行的值为null。

修复SQL,使CustomerGroup字段中没有null。

-- 预期结果
CustomerID CompanyName                     TotalOrderAmount      CustomerGroup
---------- ------------------------------- --------------------- -------------
LILAS      LILA-Supermercado               5994.06               High
LINOD      LINO-Delicateses                10085.60              Very High
LONEP      Lonesome Pine Restaurant        1709.40               Medium
...

提示如下

CustomerID为MAISD的总订单量是多少?这与我们的CustomerGroup边界有何关系?

使用“between”很适合整数值。然而,我们正在分析的字段是Money,它有小数位。因此不能使用下面的SQL:

when TotalOrderAmount between 0 and 1000 then 'Low'

而应该使用下面的SQL:

when TotalOrderAmount >= 0 and TotalOrderAmount < 1000 then 'Low'

50.使用百分比的客户分组

根据上面的查询,显示所有已定义的客户组,以及每个组中的百分比。按每一组的总数排序,按降序排序。

-- 预期结果
CustomerGroup TotalInGroup PercentageInGroup
------------- ------------ ---------------------------------------
Medium        35           0.432098765432
Low           20           0.246913580246
High          13           0.160493827160
Very High     13           0.160493827160
(4 row(s) affected)

提示如下

作为起点,你可以使用问题“客户分组-修复null”中的答案。

我们不再需要在最终的输出中显示CustomerID和CompanyName。但是,我们需要计算每个CustomerGrouping组中有多少客户。你可以创建另一个CTE级别,以便获得最终输出的每个CustomerGrouping中的计数。

51.灵活的客户分组

我们希望根据客户订购的金额来完全灵活地分组。我们不想为了更改客户组的边界而不得不编辑SQL。

你需要一个叫做客户组阈值的表(CustomerGroupThreshold),仅使用从2016年开始的订单。

-- 预期结果
CustomerID CompanyName                        TotalOrderAmount CustomerGroupName
---------- ---------------------------------- ---------------- --------------------
ALFKI     Alfreds Futterkiste                 2302.20          Medium
ANATR     Ana Trujillo Emparedados y helados  514.40           Low
ANTON     Antonio Moreno Taquería             660.00           Low
...
WHITC     White Clover Markets                15278.90         Very High
WILMK     Wilman Kala                         1987.00          Medium
WOLZA     Wolski Zajazd                       1865.10          Medium
(81 row(s) affected)

作为起点,使用问题“使用百分比的客户分组”中的第一个CTE语句

SelectCustomers.CustomerID,Customers.CompanyName,TotalOrderAmount = SUM(Quantity * UnitPrice)
From Customersjoin Orderson Orders.CustomerID = Customers.CustomerIDjoin OrderDetailson Orders.OrderID = OrderDetails.OrderID
WhereOrderDate >= '20160101'and OrderDate < '20170101'
Group ByCustomers.CustomerID,Customers.CompanyName

提示:当考虑如何使用CustomerGroupThreshold表时,请注意,当连接到一个表时,你不仅可以使用一个等值连接(=),还可以使用其他操作符,如between、>或< 。


答案

48.客户分组

答案

;with Orders2016 as (SelectCustomers.CustomerID,Customers.CompanyName,TotalOrderAmount = SUM(Quantity * UnitPrice)From CustomersJoin Orderson Orders.CustomerID = Customers.CustomerIDJoin OrderDetailson Orders.OrderID = OrderDetails.OrderIDWhereOrderDate >= '20160101'and OrderDate < '20170101'Group byCustomers.CustomerID,Customers.CompanyName
)
SelectCustomerID,CompanyName,TotalOrderAmount,CustomerGroup =Casewhen TotalOrderAmount between 0 and 1000 then 'Low'when TotalOrderAmount between 1001 and 5000 then 'Medium'when TotalOrderAmount between 5001 and 10000 then 'High'when TotalOrderAmount > 10000 then 'Very High'End
from Orders2016
Order by CustomerID

讨论

CTE很适合解决这个问题,但这并不是严格必要的。你也可以使用这样的SQL:

SelectCustomers.CustomerID,Customers.CompanyName,TotalOrderAmount = SUM(Quantity * UnitPrice),CustomerGroup =Casewhen SUM(Quantity * UnitPrice) between 0 and 1000 then 'Low'when SUM(Quantity * UnitPrice) between 1001 and 5000 then 'Medium'when SUM(Quantity * UnitPrice) between 5001 and 10000 then 'High'when SUM(Quantity * UnitPrice) > 10000 then 'Very High'End
From CustomersJoin Orderson Orders.CustomerID = Customers.CustomerIDJoin OrderDetailson Orders.OrderID = OrderDetails.OrderID
WhereOrderDate >= '20160101'and OrderDate < '20170101'
Group ByCustomers.CustomerID,Customers.CompanyName

这给出了相同的结果,但请注意,TotalOrderAmount被重复了5次,包括Case语句中的4次。

最好避免重复这样的计算。这些计算结果通常会非常复杂和难以阅读,而且你只想把它们放在一个地方。在一些简单的情况下,比如 Quantity * UnitPrice,这并不一定是一个问题。但大多数时候,你应该避免重复任何计算和代码。记住——“不要重复你自己”。

49.客户分组-修复null

答案

;with Orders2016 as (SelectCustomers.CustomerID,Customers.CompanyName,TotalOrderAmount = SUM(Quantity * UnitPrice)From CustomersJoin Orderson Orders.CustomerID = Customers.CustomerIDJoin OrderDetailson Orders.OrderID = OrderDetails.OrderIDWhereOrderDate >= '20160101'and OrderDate < '20170101'Group byCustomers.CustomerID,Customers.CompanyName
)
SelectCustomerID,CompanyName,TotalOrderAmount,CustomerGroup =casewhen TotalOrderAmount >= 0 and TotalOrderAmount < 1000 then 'Low'when TotalOrderAmount >= 1000 and TotalOrderAmount < 5000 then 'Medium'when TotalOrderAmount >= 5000 and TotalOrderAmount <10000 then 'High'when TotalOrderAmount >= 10000 then 'Very High'end
from Orders2016
Order by CustomerID

讨论

正如你在上述问题中所看到的那样,了解你正在处理的数据类型以及理解它们之间的差异对于获得正确的结果非常重要。使用“between”对于整数值就可以,但对于Money则不行。

50.使用百分比的客户分组

答案

;with Orders2016 as (SelectCustomers.CustomerID,Customers.CompanyName,TotalOrderAmount = SUM(Quantity * UnitPrice)From Customersjoin Orderson Orders.CustomerID = Customers.CustomerIDjoin OrderDetailson Orders.OrderID = OrderDetails.OrderIDWhereOrderDate >= '20160101'and OrderDate < '20170101'Group ByCustomers.CustomerID,Customers.CompanyName
)
,CustomerGrouping as (SelectCustomerID,CompanyName,TotalOrderAmount,CustomerGroup =casewhen TotalOrderAmount >= 0 and TotalOrderAmount < 1000 then 'Low'when TotalOrderAmount >= 1000 and TotalOrderAmount < 5000 then 'Medium'when TotalOrderAmount >= 5000 and TotalOrderAmount <10000 then 'High'when TotalOrderAmount >= 10000 then 'Very High'endfrom Orders2016-- Order by CustomerID
)
SelectCustomerGroup, TotalInGroup = Count(*), PercentageInGroup = Count(*) * 1.0/ (select count(*) from CustomerGrouping)
from CustomerGrouping
group by CustomerGroup
order by TotalInGroup desc

讨论

在答案中,我们添加了一个名为CustomerGrouping的中间CTE。CustomerGrouping被引用两次—— 一次是获取组中的客户总数,另一次是获得客户总数,作为百分比的分母。

请注意,在第二个CTE中的Order by CustomerID已经被注释掉了。如果你把它放在里面,你会得到错误。

51.灵活的客户分组

答案

;with Orders2016 as (SelectCustomers.CustomerID,Customers.CompanyName,TotalOrderAmount = SUM(Quantity * UnitPrice)From CustomersJoin Orderson Orders.CustomerID = Customers.CustomerIDJoin OrderDetailson Orders.OrderID = OrderDetails.OrderIDWhereOrderDate >= '20160101'and OrderDate < '20170101'Group byCustomers.CustomerID,Customers.CompanyName
)
SelectCustomerID,CompanyName,TotalOrderAmount,CustomerGroupName
from Orders2016Join CustomerGroupThresholdson Orders2016.TotalOrderAmount betweenCustomerGroupThresholds.RangeBottom and CustomerGroupThresholds.RangeTop
Order by CustomerID

讨论

请注意,这给出的结果与原来的问题相同。但是,不要使用Case语句中的硬编码值来定义CustomerGroups的边界,而是将它们放在表中。

这样做的好处是,你不需要在对客户进行分组的每个查询中重复以下代码,因为它是在表中定义的。

,CustomerGroup =casewhen TotalOrderAmount >= 0 and TotalOrderAmount < 1000 then 'Low'when TotalOrderAmount >= 1000 and TotalOrderAmount < 5000 then 'Medium'when TotalOrderAmount >= 5000 and TotalOrderAmount <10000 then 'High'when TotalOrderAmount >= 10000 then 'Very High'end

另外,请看看CustomerGroupThresholds中的值。

select * From CustomerGroupThresholds

请注意,关于范围底部和范围顶部,这些行之间没有重叠。如果是Money之外的数据类型(小数点后4位),可能会有间隙或重叠。


未完待续

下一讲我们接着讨论剩余的高级问题。


如果喜欢这篇文章,请不要忘记关注🧡、点赞👍和收藏📔哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/27083.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS

文章汇总 总体来看像是一种带权重的残差&#xff0c;但解决的如何高效问题的事情。 相比模型的全微调&#xff0c;作者提出固定预训练模型参数不变&#xff0c;在原本权重矩阵旁路添加低秩矩阵的乘积作为可训练参数&#xff0c;用以模拟参数的变化量。 模型架构 h W 0 x △…

游戏开发求职面试宝典:如何做好面试准备

面试的时候&#xff0c;你是否也遇到or担心会面临如下的问题: “哎,今天的面试又没有拿到offer”。 ”面试了好多回了&#xff0c;还是没有好的offer,算了随便找个工作先干着吧”。 “今年的市场行情真不行啊&#xff0c;早知道就不离职了”。 …… 出现以上的情况&#x…

趣谈网络协议

趣谈网络协议 原文链接:https://time.geekbang.org/column/intro/100020901?tabcatalog 第3讲 | ifconfig&#xff1a;最熟悉又陌生的命令行如何理解 ip addr &#xff1f;如果理解32位IP地址的5个分类&#xff1f;如何理解A&#xff0c;B&#xff0c;C三类地址的最大主机数和…

Mybatis和Hibernate的作用区别及底层原理分析

目录 Mybatis的作用及底层原理 Hibernate的作用及底层原理 Mybatis与Hibernate的主要区别 Mybatis和Hibernate都是Java应用程序中常用的ORM&#xff08;Object-Relational Mapping&#xff0c;对象关系映射&#xff09;框架&#xff0c;它们的主要作用是简化数据库访问层的开…

XXE漏洞详解:从基础到防御

引言 在网络安全领域&#xff0c;XXE&#xff08;XML External Entity&#xff09;漏洞是一种常见的安全风险&#xff0c;它允许攻击者通过XML文档读取服务器上的文件&#xff0c;甚至执行远程服务器请求。本文将深入探讨XXE漏洞的基本概念、攻击手段以及如何有效防御。 XXE漏…

31、shell循环

一、循环 循环&#xff1a;循环是一种重复执行一段代码的结构。只要满足循环的条件&#xff0c;会一直执行这个代码。 循环条件&#xff1a;在一定范围之内&#xff0c;按照指定的次数来执行循环。 循环体&#xff1a;在指定的次数内&#xff0c;执行的命令序列。只要条件满…

深入解析 Spring Cloud Seata:分布式事务的全面指南

&#x1f9e8;&#x1f9e8;&#x1f9e8;深入解析 Spring Cloud Seata&#xff1a;分布式事务的全面指南 在微服务架构中&#xff0c;分布式事务的处理是一项复杂而重要的任务。Spring Cloud Seata 是一款专为分布式事务而设计的解决方案&#xff0c;它由阿里巴巴开源&#x…

记录一次网络延迟的事件分析

场景&#xff1a;几天前&#xff0c;某资源池的服务器ping 延迟500ms以上&#xff0c;感觉网络有问题&#xff0c;同时查看服务器的负载&#xff0c;发现不高&#xff0c;带宽也没有超限。 排查经过&#xff1a;仔细分析&#xff0c;查看日志&#xff0c;发现是一些延迟的信息…

宏电“灌区哨兵”助力灌区信息化建设,开启灌区“智水”时代

灌区是保障国家粮食安全的重要水利设施。“十四五”提出&#xff0c;要推进大中型灌区节水改造和精细化管理。灌区信息化是建设智慧水利、深化行业监管、提升灌区科学管理水平的基础支撑&#xff0c;也是“十四五”期间灌区现代化改造的重点内容之一。 宏电智慧灌区信息化解决方…

2024脑卒中评估量表分享

常笑医学整理了5个常用的脑卒中评估量表&#xff0c;供临床医护工作人员参考。 Essen脑卒中风险评分量表-常笑医学网​ &#xff08;完整量表请点击量表名称查看&#xff09; Essen脑卒中风险评估量表&#xff0c;是一个简便、易于临床操作的9分量表&#xff0c;是根据氯吡格雷…

k8s nginx.conf配置文件配置

无状态nginx配置nginx.conf覆盖容器配置nginx.conf 代码&#xff1a;events {worker_connections 1024; }http {include /etc/nginx/mime.types;default_type application/octet-stream;log_format main $remote_addr - $remote_user [$time_local] "$request&q…

什么是JWT?为什么用JWT?JWT的实战案例

JWT学习资料 1.什么是JWT?【头部(Header)、载荷(Payload)和签名(Signature)】2.为什么要用JWT?3.JWT 使用全局变量JWT 创建JWT的应用&#xff08;token放在返回信息中&#xff09;JWT验证 4.JWT 原理 1.什么是JWT?【头部(Header)、载荷(Payload)和签名(Signature)】 JWT(JS…

reGeorg隐秘隧道搭建

reGeorg隐秘隧道搭建 【实验目的】 通过学习reGeorg与Proxifier工具使用&#xff0c;实现外网攻击端连接内网主机远程桌面。 【知识点】 python、reGeorg、proxifier。 【实验原理】 在内网渗透中&#xff0c;由于防火墙的存在&#xff0c;导致无法对内网直接发起连接&#xff…

【康复学习--LeetCode每日一题】2786. 访问数组中的位置使分数最大

题目描述&#xff1a; 给你一个下标从 0 开始的整数数组 nums 和一个正整数 x 。 你一开始 在数组的位置 0 处&#xff0c;你可以按照下述规则访问数组中的其他位置&#xff1a; 如果你当前在位置 i &#xff0c;那么你可以移动到满足 i < j 的 任意 位置 j 。 对于你访问的…

Linux多线程编程中的同步与互斥

文章目录 一、线程同步与互斥1、理解线程同步2、互斥的概念3、小结 二、互斥锁&#xff08;Mutex&#xff09;1、互斥锁的定义和作用2、pthread库中的互斥锁3、互斥锁的实现原理4、示例代码演示互斥锁的基本用法 三、条件变量&#xff08;Condition Variable&#xff09;1、条件…

IDEA 配置方法模板无法获取到参数值和返回值(methodParameters()、methodReturnType()获取不到值)

问题现象&#xff1a; 我在 review 同事代码时候&#xff0c;发现方法上有注释&#xff0c;但是注释上又没有方法参数和返回值&#xff0c;这不是IDEA 配置了方法模板就可以自动生成的嘛&#xff0c;我出于好奇去问了下该同事是怎么回事&#xff0c;该同事有点不好意思的说我配…

Nginx正向代理配置示例与说明

Nginx的正向代理配置示例和说明如下&#xff1a; 配置示例 配置文件&#xff08;nginx.conf&#xff09; server {resolver 114.114.114.114; # 指定DNS服务器IP地址resolver_timeout 5s; # 设置DNS服务器域名解析超时时间listen 80; # 监听HTTP的80端口…

【JAVA】Java中Spring Boot如何设置全局的BusinessException

文章目录 前言一、函数解释二、代码实现三、总结 前言 在Java应用开发中&#xff0c;我们常常需要读取配置文件。Spring Boot提供了一种方便的方式来读取配置。在本文中&#xff0c;我们将探讨如何在Spring Boot中使用Value和ConfigurationProperties注解来读取配置。 一、函数…

昂辉科技EasySAR-BootLoader上位机产品

近年来&#xff0c;硬件标准化、同质化和软件差异化、复杂化成为了汽车产品研发的重要趋势。与此同时&#xff0c;大量的智能化功能和快速上车的节奏&#xff0c;对软件开发提出了更高的要求。在软硬件解耦的大背景下&#xff0c;建立统一的软件体系和开发工具以紧跟硬件更新迭…

Linux怎么编辑所有行行尾内容

Linux怎么编辑所有行行尾内容 1. sed2. Visual Block 模式 ctrlv 1. sed sed 是一个流编辑器&#xff0c;它可以逐行处理文本文件。要在所有行的行尾添加内容&#xff0c;可以使用 sed 的替换功能。 想在每一行的行尾添加一些内容&#xff0c;例如添加字符串 "END"。…