[数据库萌新入门] 第二章 表联结查询

一、子查询:

把一个sql语句的结果,作为外层sql语句的条件。

作为计算字段使用子查询

# 获取每个用户的订单总数

# 如果分开查询我们需要像下面这样,根据第一行的结果,手动重复第二行sql,

# 相当于对第一行sql的每一行结果,都执行一遍第二行sql

select cust_id,cust_name from customers;
select count(*) as orders_num from orders where cust_id = 10001;

# 把上述两段sql,合成成下面这条sql

# 复杂度的话,相当于对主查询语句中的每一行 , 都执行一遍子查询。

select cust_id,cust_name,
       (select count(*) from orders where orders.cust_id = customers.cust_id) as orders_num
from customers;

二、表关系:

外键:

 在一个表中,定义一个字段,这个字段中存储的数据是另外一张表中的主键

就是在一个表中的字段,代表着这行数据属于谁。

了解:外键实现的方式

1、物理外键     2、逻辑外键

物理外键:就是在创建表时,就指定这个表中的字段是一个外键,并且强关联某个表中的某个字段。

                需要在定义字段时,使用sql语句来实现。(不推荐,并发时可能降低效率)

逻辑外键:就是在表中创建一个普通的字段,没有强关联关系,需要通过程序逻辑来实现。

一对一:

在一个表中的数据,只能对应着另外一张表中的一个数据。(比如,另一个表中有个外键,是唯一的)

一对多:

在一个表中的一行数据,对应着另一个表中的多行数据。(比如,另一个表中有个外键,是重复多次的)

在一个表中的多行数据,对应着另一个表中的一行数据。

多对多:

例如:一本书,有多个标签,同时每一个标签下又对应多本书

是两张表,互相,一行数据对对面多行数据。

三、表联结

一个示例:

select vend_name,prod_name,prod_price
from vendors,products
where vendors.vend_id = products.vend_id
order by vend_name;

上面的语句,用 where 限定了 我们要查询的 三个字段 之间的逻辑。使之成表。

假如没有where条件时会发生什么呢?

select vend_name, prod_name, prod_price from vendors, products;

如果没有where条件,那么第一个表中的每一行数据会与第二个表中的每一行数据进行匹配,不管逻辑是否可以匹配

如果没有where条件,那么这种结果称为 笛卡尔积 ,结果数量为第一个表的行数乘以第二个表中的行数。

所以千万不能忘记where条件

 

另一种方式是使用 join 关键字, 在 on 后面 定义 联结条件。

select vend_name,prod_name,prod_price
from vendors
inner join products on vendors.vend_id = products.vend_id;

实例: 查询订单号为20005的订单中 购买的商品 及 商品对应的 供应商 信息。

第一步:先写出需要得到的信息,及他们所在的表

select prod_name,vend_name,prod_price,quantity
from orderitems,products,vendors

第二步:根据我们要的字段,补充表与表之间的逻辑关系,(表1 中 特定字段a 和 表2 中 特定字段b 的关系)

select prod_name,vend_name,prod_price,quantity
from orderitems,products,vendors
	where products.vend_id = vendors.vend_id
	and orderitems.prod_id = products.prod_id
	and order_num = 20005;

完成。

上面的语句改写成 join 如下: (单独 join 默认为 inner join)

select prod_name,vend_name,prod_price,quantity
from orderitems 
join products on orderitems.prod_id = products.prod_id
join vendors on products.vend_id = vendors.vend_id
where order_num = 20005;

 

自联结:

假如你发现某物品(其ID为DTNTR)存在问题,因此想知道生产该物品的供应商生产的其他物品是否也存在这些问题。

此查询要求首先找到生产ID为DTNTR的物品的供应商,然后找出这个供应商生产的其他物品。

-- 使用子查询

select prod_id,prod_name
from products
where vend_id = (
	select vend_id from products
	where prod_id = 'DTNTR');

-- 自联结查询

select p1.prod_id,p1.prod_name
from products as p1
join products as p2 on p1.vend_id = p2.vend_id
where p2.prod_id = 'DTNTR';

或者是:

select p1.prod_id,p1.prod_name
from products as p1, products as p2
where p1.vend_id = p2.vend_id and p2.prod_id = 'DTNTR';

为什么上面我们全选 p1 表的数据呢?

-- 深入理解一下表联结:

# 第一步


select p1.prod_id,p1.prod_name,p1.vend_id,
p2.prod_id,p2.prod_name,p2.vend_id
from products as p1, products as p2;

# 第二步

select p1.prod_id,p1.prod_name,p1.vend_id,
p2.prod_id,p2.prod_name,p2.vend_id
from products as p1, products as p2
where p1.vend_id = p2.vend_id;

# 第三步

select p1.prod_id,p1.prod_name,p1.vend_id,
p2.prod_id,p2.prod_name,p2.vend_id
from products as p1, products as p2
where p1.vend_id = p2.vend_id
and p2.prod_id = 'DTNTR';

第三步的运行结果如下:  

左边三列是 p1 表, 右边三列是 p2 表。

以上三步逻辑为: p1 表和 p2 表先进行笛卡儿积,得到一张超大表,

                               然后在超大表中,取出 两边 vend_id 相等的行,得到一张中等大小的表

                            再进一步从中取出行中 p2 的 prod_id 为 DTNTR 的数据。 所以根据这个表,我们要取的列均在 p1 中。

DTNTR    Detonator    1003    DTNTR    Detonator    1003
FB    Bird seed    1003    DTNTR    Detonator    1003
FC    Carrots    1003    DTNTR    Detonator    1003
SAFE    Safe    1003    DTNTR    Detonator    1003
SLING    Sling    1003    DTNTR    Detonator    1003
TNT1    TNT (1 stick)    1003    DTNTR    Detonator    1003
TNT2    TNT (5 sticks)    1003    DTNTR    Detonator    1003

        或者这样思考: p2 表中,因为我们限定要 p2.prod_id = 'DTNTR',所以 p2 表的数据固定为 DTNTR 了。那肯定不能从 p2 拿数据,否则必然拿到的是重复数据。

注意:

       子查询(嵌套查询) 是目前可明确知道的sqL中运行效率最低的一种方式,尽可能不使用嵌套语句。

 

外部联结:

      内部联结(where)只能对两个表中相关联的数据进行查询。

      当联结包含了了那些在相关表中没有关联行的行。这种类型的联结称为外部联结。

      什么是没有关联呢? 可以理解为, 表 B 有 外键 指向 表 A, 但是 表 B 中的外键,不能覆盖 表 A 的所有主键。

外部联结分为: 

left join:

     以 left join 左侧的表为基准,去关联右侧的表,进行联结,如果有未关联的数据,那么结果为null(即,空处补null)

     左联结可以保证左表数据不丢。

right join

     以 right join 右侧的表为基准,去关联左侧的表,进行联结,如果有未关联的数据,那么结果为null(即,空处补null)

     相对应地,右联结保证右表数据不丢。

 

聚集函数可以和联结一起使用。

  1. 保证使用正确的联结条件,否则将返回不正确的数据。
  2. 应该总是提供联结条件,否则会得出笛卡儿积。
  3. 在一个联结中可以包含多个表,甚至对于每个联结可以采用不同的联结类型。虽然这样做是合法的,一般也很有用,但应该在一起测试它们前,分别测试每个联结。这将使故障排除更为简单

组合查询UNION:

MySQL也允许执行多个查询(多条SELECT语句) ,并将结果作为单个查询结果集返回。
这些组合查询通常称为并(union)或复合查询(compound query)

  1. UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔(因此,如果组合4条SELECT语句,将要使用3个UNION关键字)。
  2. UNION中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)
  3. 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含地转换的类型(例如,不同的数值类型或不同的日期类型)

进一步解释:

两个 select 语句 原封不动 中间用 union 关键字 拼接 即可。

可拼接条件描述:两个 select 语句返回的结果表,假如是 表 A 和 表 B 必须:

  1. A、B总列数相同
  2. A 中所有列的列名, 和 B 中所有列的列名一致。
  3. A 和 B 返回的 同名列 的 顺序 不必一致。
  4. 除开是已有的列,也可以是满足以上相同条件的表达式或者聚集函数
  5. 针对第4条,结果列数据类型必须兼容(只要DBMS可以隐式转换即可)

ORDER BY 子句只能在 最后一条 select 语句之后出现, 且 它将应用至 最终结果集 的所有数据。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值