【SQL边干边学系列】02介绍性问题(续)


前言

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

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

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

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

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


回顾

上篇文章👉《【SQL边干边学系列】01介绍性问题》 讨论了部分介绍性问题,这篇我们接着讨论剩余的介绍性问题。


介绍性问题

7.产品名称中包含“queso”的产品

在产品表(products)中,我们希望看到那些产品名称(ProductName)中包含字符串“queso”的产品的产品标识(ProductID)和产品名称(ProductName)。

-- 预期结果
ProductID   ProductName
----------- ----------------------------------------
11          Queso Cabrales
12          Queso Manchego La Pastora
(2 row(s) affected)

提示:在前面的一个问题中,我们正在寻找精确的匹配(过滤器与字段中的值精确匹配)。在这里,我们正在寻找产品名称字段中包含“queso”的那些行。在答案中使用带有通配符的“like”运算符。

8.运往法国或比利时的订单

看看订单表(Orders),有一个列叫做目的地(ShipCountry)。编写一个查询,显示目的地为法国(France)或比利时(Belgium)的订单的订单ID(OrderID)、客户ID(CustomerID)和目的地(ShipCountry)。

-- 预期结果
OrderID     CustomerID ShipCountry
----------- ---------- ---------------
10248       VINET      France
10251       VICTE      France
10252       SUPRD      Belgium
10265       BLONP      France
.......
11043       SPECD      France
11051       LAMAI      France
11076       BONAP      France
(96 row(s) affected)

提示: 在where子句中,使用Or将过滤器连接起来。

9.运往拉丁美洲任何国家的订单

现在,我们想展示来自任何一个拉丁美洲国家的所有订单。拉丁美洲国家列表:巴西(Brazil),墨西哥(Mexico),阿根廷(Argentina)和委内瑞拉(Venezuela)。

不能再使用"Or"语句,它会变得太复杂,应该使用“In”语句。

-- 预期结果
OrderID     CustomerID ShipCountry
----------- ---------- ---------------
10250       HANAR      Brazil
10253       HANAR      Brazil
10256       WELLI      Brazil
......
11071       LILAS      Venezuela
11073       PERIC      Mexico
(173 row(s) affected)

10.员工,按年龄的顺序排列

对于“员工”表(employees)中的所有员工,请显示FirstName、LastName、头衔(Title)和出生日期(BirthDate)。按出生日期排序,所以我们先看到最年长的员工。

-- 预期结果
FirstName  LastName             Title                          BirthDate
---------- -------------------- ------------------------------ -----------------------
Margaret   Peacock              Sales Representative           1955-09-19 00:00:00.000
Nancy      Davolio              Sales Representative           1966-12-08 00:00:00.000
Andrew     Fuller               Vice President, Sales          1970-02-19 00:00:00.000
Steven     Buchanan             Sales Manager                  1973-03-04 00:00:00.000
Laura      Callahan             Inside Sales Coordinator       1976-01-09 00:00:00.000
Robert     King                 Sales Representative           1978-05-29 00:00:00.000
Michael    Suyama               Sales Representative           1981-07-02 00:00:00.000
Janet      Leverling            Sales Representative           1981-08-30 00:00:00.000
Anne       Dodsworth            Sales Representative           1984-01-27 00:00:00.000
(9 row(s) affected)

11.让DateTime列仅显示Date

在上面的查询的输出中,按出生日期的顺序显示员工,展示了BirthDate字段(Datetime类型),我们只想显示Date,不想显示Time。

--- 预期结果
FirstName   LastName            Title                          DateOnlyBirthDate
---------- -------------------- ------------------------------ -----------------
Margaret   Peacock              Sales Representative           1955-09-19 
Nancy      Davolio              Sales Representative           1966-12-08 
Andrew     Fuller               Vice President, Sales          1970-02-19 
Steven     Buchanan             Sales Manager                  1973-03-04 
Laura      Callahan             Inside Sales Coordinator       1976-01-09 
Robert     King                 Sales Representative           1978-05-29
Michael    Suyama               Sales Representative           1981-07-02 
Janet      Leverling            Sales Representative           1981-08-30 
Anne       Dodsworth            Sales Representative           1984-01-27 
(9 row(s) affected)

提示:使用“转换函数”可以将“BirthDate”列转换为“Date”列

12.员工全名

显示Employees表中的FirstName和LastName列,然后创建一个名为FullName的新列,显示FirstName和LastName连接在一起的效果,中间有一个空格。

-- 预期结果
FirstName   LastName            FullName
---------- -------------------- -------------------------------
Nancy      Davolio              Nancy Davolio
Andrew     Fuller               Andrew Fuller
Janet      Leverling            Janet Leverling
Margaret   Peacock              Margaret Peacock
Steven     Buchanan             Steven Buchanan
Michael    Suyama               Michael Suyama
Robert     King                 Robert King
Laura      Callahan             Laura Callahan
Anne       Dodsworth            Anne Dodsworth
(9 row(s) affected)

13.每个订单的详细金额

在订单详细信息表(OrderDetails)中,我们有字段的单位价格(UnitPrice)和数量(Quantity)。创建一个新的字段,总价格(TotalPrice),它将这两个值相乘。我们现在将忽略折扣字段。此外,还可以显示订单ID(OrderID)、产品ID(ProductID)、单位价格(UnitPrice)和数量(Quantity)。按订单ID(OrderID)和产品标识(ProductID)排序。

-- 预期结果
OrderID     ProductID   UnitPrice             Quantity TotalPrice
----------- ----------- --------------------- -------- ---------------------
10248       11          14.00                 12       168.00
10248       42          9.80                  10       98.00
10248       72          34.80                 5        174.00
...
11077       75          7.75                  4        31.00
11077       77          13.00                 2        26.00
(2155 row(s) affected)

14.有多少客户?

我们的客户表(Customers)中有多少个客户?只显示一个值,并且不要依赖于返回结果最后附带的统计计数。

-- 预期结果
TotalCustomers
--------------
91
(1 row(s) affected)

提示:为了获得客户的总数,我们需要使用所谓的聚合函数。

15.第一个订单是什么时候?

显示在订单表(Orders)中创建的第一个订单的日期。

-- 预期结果
FirstOrder
-----------------------
2014-07-04 08:00:00.000
(1 row(s) affected)

提示:有一个叫做Min的聚合函数来解决这个问题。

16.已有客户的国家

显示该公司拥有客户的国家名单。

-- 预期结果
Country
---------------
Argentina
Austria
Belgium
Brazil
Canada
Denmark
Finland
France
Germany
Ireland
Italy
Mexico
Norway
Poland
Portugal
Spain
Sweden
Switzerland
UK
USA
Venezuela
(21 row(s) affected)

提示:需要使用 Group By 子句。

17.统计每个ContactTitle的数量

显示“Customers”表中“ContactTitles”列的所有不同值,还包括每个值的统计数。

-- 预期结果
ContactTitle                   TotalContactTitle
------------------------------ -----------------
Owner                          17
Sales Representative           17
Marketing Manager              12
Sales Manager                  11
Accounting Manager             10
Sales Associate                7
Marketing Assistant            6
Sales Agent                    5
Assistant Sales Agent          2
Order Administrator            2
Assistant Sales Representative 1
Owner/Marketing Assistant      1
(12 row(s) affected)

提示:需要使用分组、聚合函数和别名。

18.产品与相关供应商名

我们想展示每个产品的相关供应商。显示供应商的ProductID、ProductName和CompanyName,按ProductID排序。

这个问题将介绍一个新的概念,即SQL中的Join子句。Join子句用于以逻辑的方式将两个或多个关系数据库表连接在一起。

-- 预期结果
ProductID    ProductName                             Supplier
----------- ---------------------------------------- ------------------------------
1           Chai                                     Exotic Liquids
2           Chang                                    Exotic Liquids
3           Aniseed Syrup                            Exotic Liquids
...
74          Longlife Tofu                            Tokyo Traders
75          Rhönbräu Klosterbier                     Plutzer Lebensmittelgroßmärkte AG
76          Lakkalikööri                             Karkki Oy
77          Original Frankfurter grüne Soße          Plutzer Lebensmittelgroßmärkte AG
(77 row(s) affected)

答案

7.产品名称中包含“queso”的产品

答案

Select
 ProductID 
 ,ProductName 
From Products 
Where
 ProductName like '%queso%'

讨论

“Like”运算符总是与通配符一起使用,例如百分比符号(%),它可以替换任意数量的字符。

请注意,即使搜索字符串使用了一个小写的“q”和一个类似的子句ProductName like '%queso%',得到的结果也可能包含大写Q。例如:

Queso Cabrales
Queso Manchego La Pastora

这是因为SQL Server的默认安装不区分大小写,尽管也可以安装为区分大小写。

8.运往法国或比利时的订单

答案

Select
 OrderID
 ,CustomerID
 ,ShipCountry
From Orders
where
 ShipCountry = 'France'
 or ShipCountry = 'Belgium'

讨论

这是一个非常简单的例子,但在许多情况下,将有多个where子句,并用“Or”和“And”连接起来。

在这种情况下,另一种替代方法是使用“In”运算符。

9.运往拉丁美洲任何国家的订单

答案

Select
 OrderID
 ,CustomerID
 ,ShipCountry
From Orders
where
 ShipCountry in
 (
 'Brazil'
 ,'Mexico'
 ,'Argentina'
 ,'Venezuela'
 )

讨论

在编写SQL时,像这样使用“In”语句是一个非常常见的场景,通常把值放在单独的行上,以便让它更容易阅读、理解和修改。

10.员工,按年龄的顺序排列

答案

Select
 FirstName
 ,LastName
 ,Title
 ,BirthDate
From Employees
Order By Birthdate

讨论

这是一个按顺序排列的简单例子。

默认情况下,SQL Server按升序排序。要按降序排列,请使用desc关键字:

Select
 FirstName
 ,LastName
 ,Title
 ,BirthDate
From Employees
Order By Birthdate desc -- desc代表降序

11.让DateTime列仅显示Date

答案

Select
 FirstName
 ,LastName
 ,Title
 ,DateOnlyBirthDate = convert(date, BirthDate)
From Employees
Order By Birthdate

讨论

我们在这里使用的是计算列(相对于返回列来说)。在这种情况下,我们正在使用一个函数来转换返回的数据类型。

请注意,我们已经为计算列添加了一个名称(DateOnlyBirthDate),这被称为别名。

DateOnlyBirthDate = convert(date, BirthDate)

如果你没有指定列别名,那么将得到一个空的列头,这非常不利于阅读。

12.员工全名

答案

Select
 FirstName 
 ,LastName 
 ,FullName = FirstName + ' ' + LastName 
From Employees

讨论

这是已计算的列的另一个示例。在这种情况下,我们不是对一个字段使用一个函数,而是连接两个字段。

13.每个订单的详细金额

答案

Select
 OrderID
 ,ProductID
 ,UnitPrice
 ,Quantity
 ,TotalPrice = UnitPrice * Quantity
From OrderDetails
Order by
 OrderID 
 ,ProductID

讨论

这里我们有另一个计算列的例子,这次使用算术算子“*”来进行乘法。

当然,你也可以使用“as”语句:

Select
 OrderID
 ,ProductID
 ,UnitPrice
 ,Quantity
 ,UnitPrice * Quantity as TotalPrice -- Alias using "as"
From OrderDetails
Order by
 OrderID
 ,ProductID

14.有多少客户?

答案

Select
 TotalCustomers = count(*)
from Customers

15.第一个订单是什么时候?

答案

Select
 FirstOrder = min(OrderDate)
From Orders

16.已有客户的国家

答案

Select
 Country
From Customers
Group by
 Country

讨论

Group By子句是SQL的基石。对于任何复杂度的分析,你将使用多个 Group By子句,因此理解它们很重要。

17.统计每个ContactTitle的数量

答案

Select
 ContactTitle
 ,TotalContactTitle = count(*)
From Customers
Group by
 ContactTitle
Order by
 count(*) desc

讨论

这种特殊的构造,有一个分组,然后是每个组的总数的计数,它本身和作为其他查询的一部分都是非常常见的。

18.产品与相关供应商名

答案

Select
 ProductID
 ,ProductName
 ,Supplier = CompanyName
From Products
 Join Suppliers
 on Products.SupplierID = Suppliers.SupplierID

讨论

连接可以非常简单,也可以非常复杂。你需要彻底地理解它们,因为除了最简单的SQL之外,它们对编写任何东西都至关重要。

当你阅读SQL代码时,你也会看到这样的答案:

Select
 ProductID
 ,ProductName
 ,Supplier = CompanyName
From Products P -- 别名表
 Join Suppliers S -- 别名表
 on P.SupplierID = S.SupplierID

如果这样做,也需要在On子句中使用P和S。

尽管这很常见,但是我不喜欢这种风格。唯一的好处是避免了一些重复输入,但缺点很严重,它导致代码更难阅读。

在像这样的小块SQL中,这并不是什么问题。然而,在长而复杂的SQL中,你会发现自己想知道一个字母的别名是什么意思,总是需要查阅From子句,并在脑海中翻译。


未完待续

下次我们接着讨论中级问题。


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

架构师昌哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值