SQL学习之学会使用子查询
1、SELECT语句是SQL的查询。我之前的随笔中所用的SELECT语句都是简单的查询,即从单个数据库表中检索数据的单条SELECT语句。
查询:任何SQL语句都是查询,但此术语一般指SELECT语句。
2、SQL不仅允许简单的SELECT查询,还允许创建子查询,即嵌套在其他查询中的查询。
下面通过实例来了解子查询在实际项目中的应用:
create database Study
go
use Study
go
create table Customers(
Id int identity(1,1),
Name varchar(10) null
)
insert into Customers values('张三')
insert into Customers values('李四')
insert into Customers values('王五')
insert into Customers values('赵六')
insert into Customers values('冯七')
select * from Customers
create table Products(
Id int identity(1,1),
Name varchar(255) null
)
insert into Products values('产品一')
insert into Products values('产品二')
insert into Products values('产品三')
insert into Products values('产品四')
insert into Products values('产品五')
select * from Products
create table Orders(
Id int identity(1,1),
CustomerId int null,
AddDate datetime null
)
insert into Orders values(1,GETDATE())
insert into Orders values(2,GETDATE())
insert into Orders values(3,GETDATE())
insert into Orders values(4,GETDATE())
insert into Orders values(5,GETDATE())
select * from Orders
create table OrderItems
(
Id int identity(1,1),
OrderId int null,
ProductId int null
)
insert into OrderItems values(1,1)
insert into OrderItems values(1,2)
insert into OrderItems values(1,3)
insert into OrderItems values(2,3)
insert into OrderItems values(3,2)
insert into OrderItems values(4,1)
select * from OrderItems
这是分析SQL子查询所需要用到的sql文件。
这是4个表的基础数据
需求:现在我们需要列出订购产品Id为1的所有顾客,下面是基本的思路:
(1)先去OrderItems(中间表)检索产品Id为'1'的所有的订单编号,代码如下:
select Id,orderId from OrderItems where ProductId=1
(2)拿到(1)步骤所有的订单Id编号之后,再根据检索出来的订单Id,去Orders(订单表)查找对应的顾客Id(是那些顾客下了这些订单),代码如下:
select CustomerId from Orders where Id in (select orderId from OrderItems where ProductId=1)
注意下面这种写法是错的:
select CustomerId from Orders where Id in (select Id,orderId from OrderItems where ProductId=1)
这就相当于判断Id==Id,orderId这种写法是错的!
DMBS控制台报的错误信息:当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式。告诉你子查询中的选择列表只能指定一个表达式!
(3)拿到所有顾客Id之后,再根据这些顾客Id,去Customers(顾客表)中检索顾客的详细信息,代码如下:
select * from Customers Where Id in (select CustomerId from Orders where Id in (select orderId from OrderItems where ProductId=1))
ok!完成了上面提出的需求
但是有一点不足的是如果查询的深度很深,代码就会很长,像上面的书写代码的方式,不易于我们阅读,有如下代码:
select *
from Customers
Where Id IN(select CustomerId
from Orders
where Id IN(select orderId
from OrderItems
where ProductId=1))
这段代码层次分明,比之前的代码更加的容易理解!
3、下面是使用子查询必须知道的几点:
(1)很重要的一点,作为子查询的SELECT语句只能查询单个列。企图检索多个列将返回错误(上面列子中的第(2)步已给出证明)。
(2)子查询的性能:上面给出的列子中的代码有效,并且获得了所需的结果。但是使用子查询并不总是执行这类数据检索最有效的方法。
所以,这里我使用内联结的方式完成上面所提出的需求,代码如下:
select * from
dbo.Customers a INNER JOIN
dbo.Orders b ON a.Id=b.CustomerId INNER JOIN
dbo.OrderItems c ON c.OrderId=b.Id
where c.ProductId=1
这里我的表数据有点变动,所以只看代码的逻辑即可!
4、下面改变当前随笔2中的需求,需要显示Customers表中的每个顾客的订单总数。
简单分析下思路,因为Customers表中没有订单总数这个字段,所以目前我们只能用一个计算字段来代替订单总数,而这个计算字段的列值必须是每个顾客的订单总数。
(1)先从Customers表中检索出顾客列表Id
(2)对于检索出来的每个顾客,统计其在Orders表中的订单数目
一般情况下统计一个顾客在Orders(订单表)中的订单总数,可以这样做:
select count(*) from Orders where CustomerId=1
上面代码统计了顾客编号为1的订单总数,但是这里需要统计的是所有用户的订单总数,显然这样写不对,我们可以这样写:
select name,(select COUNT(*) from Orders where Orders.CustomerId=Customers.Id) as orders from Customers
这段代码实际并不能检索出来结果,因为他将一个计算字段,被插入到其他的SELECT语句中一起被返回,该查询对对检索出的每个顾客ID执行一次 select COUNT(*) from Orders where dbo.Orders.CustomerId=当前顾客Id的运算;因为有5个顾客,所以会进行5次运算。返回每个顾客的总订单数。
下面是完整代码:
select name,(select COUNT(*) from Orders where Orders.CustomerId=Customers.Id) as orders from Customers
子查询中的WHERE子句(where Orders.CustomerId=Customers.Id)与前面使用的WHERE子句稍有不同,因为它使用了完全限定列名,而不只是列名。他指定列名和表名(Orders.CustomerId和Customers.Id),这个Where子句等于告诉SQL比较Orders的CustomerId和当前正从Customers表中检索的Id
- React第三方组件5(状态管理之Redux的使用⑥Redux DevTools)
- React第三方组件5(状态管理之Redux的使用⑤异步操作)
- HDU - 1846 Brave Game
- React多页面应用4(webpack4 提取第三方包及公共组件)
- zoj 2420
- SPOJ NWERC11B Bird tree
- React多页面应用6(gulp自动化发布到多个环境、生成版本号、压缩成zip等)
- SDIBT 1046 Primary Arithmetic
- 洛谷P2415 集合求和
- React多页面应用5(webpack生产环境配置,包括压缩js代码,图片转码等)
- SDIBT 1046 Primary Arithmetic
- React多页面应用4(webpack自动化生成多入口页面)
- 第二周神经网络基础2.1 二分分类2.2 logistic回归2.3 logistic 回归损失函数2.4 梯度下降2.5 导数2.14 向量化logistic 回归的输出2.15 Python中的广
- 1031 SDIBT Where's Waldorf?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- TypeScript 实战算法系列(三):实现链表与变相链表
- JavaScript 测试系列实战(一):使用 Jest 和 Enzyme 测试 React 组件
- TypeScript 实战算法系列(二):实现队列与双端队列
- VBA位操作
- VBA编写Ribbon Custom UI编辑器07——写入xml
- Linux下在文件夹所有文件中查找相关内容
- archlinux安装篇(一) 基本系统
- git使用要点
- 七夕 - 程序员表白代码
- Shell流程控制
- Shell sed命令
- focus/focusin/focusout
- once
- c语言之指向二维数组元素的指针变量
- c语言之在函数内部改变数组的值从而影响外部数组的四种方式