MySQL ------ 联结(join)(内联结 inner join)(十四)

联结(join) : 一种机制,在数据检索查询中执行,将表与表之间关联起来

说到将表关联起来,就有了主外键 ,为啥会有来,因为只用一个表很难做成一个系统,当然也可以,这样的话这个表肯定不符合建表的三大范式,所以一般都是尽量满足三大范式,让数据库不冗余,表也很清爽,就向软件中的高内聚低耦合,不容易崩,还有就是当你走了,下一个在来他的理解成本也会降低,(其实各有各的好处吧,毕竟查一个表是最简单的),因此分开后,表与表之间的关联就要靠主外键,

外键(foreign key): 外键为某个表中的一列,它包含另一个表的主键值,定义了两个表之间的关系。

主键(primary key): 能够唯一区分表中每一个行的一个列

像 供应商与产品,他们之间肯定会靠主外键互相关联,如果放在一个表里

  1、同一个供应商生产的每个产品它的供应商信息都是相同的,重复的浪费时间也浪费空间

  2、如果供应商的信息改变,之前的存储的商品也要改,不够灵活,容错性小,维护成本高

  3、如果有重复数据。很难保证每次输入该数据的方式都相同, 使用不方便,数据可能重复,出现不一致

还有就是,关系型数据库设计的基础,就是避免出现重复数据,关系表的的设计就是把信息分解成多个表,一类数据一个表,各表通过某些常用的值相互关联,关系数据可以有效的存储和方便地处理,因此关系数据库的可伸缩性远比非关系数据库要好。

可伸缩性(scale):能够适应不断增加的工作量而不失败。设计良好的数据库或应用程序称之为可伸缩性好(scale well)

如上所述,分解数据为多个表可以更有效的存储,更方便地处理,并且具有更大的可伸缩性,那么如何使用一条语句进行查询这多表的数据来,你可能想到了之前将的子查询,但是本篇的文章可是联结,所以这种用来在一条select 语句中关联表的机制称为联结,在运行时要使用正确的行(常用的就是主外键)

注意:

  1、联结不是物理实体,他在实际数据表中并不存在,联结由mysql根据需要建立,存在于查询的执行中

  2、要维护引用的完整性,如商品表的供应商要是供应商表中的数据

1、简单使用

 用到的表,供应商与商品表时一对多的关系,一个供应商有多条产品记录

 

 使用联结查询时    两个表使用 ,号分隔,查询使用完全限定将两个表的共有属性作为查询条件

-- 查询vendors,products 两个表,将两个表中vend_id 相同的检索出来
select vend_name,prod_name from vendors,products  where products.vend_id = vendors.vend_id order by vend_name,prod_name;

 注意:在引用的列中可能出现二义性,必须使用完全限定,(表名,列名),没有使用会报错

ERROR 1052 (23000): Column 'vend_id' in where clause is ambiguous

还有就是要注意:检索的字段也不要具有二义性,不然也会报错,

就像下面一样,vend_id 是两个表的共有字段,你不指定他就蒙了

 

 !!!

为啥要用where 子句建立连接:在使用一条SQL 语句连接几个表时,相应的关系是在运行中构造的,在数据库表的定义中不存在能指示MySQL 如何对表进行连接东西,你必须要自己做这件事,在联结两个表时,你实际上做的是将第一个表中的每一行与第二个表中的每一行配对,where 子句作为过滤条件,它指包含那些匹配给定条件(即联结条件)的行。没有where 子句,第一个表中的每个行将与第二个表中的每个行配对,而不管他们是否可以配对在一起。这个现象也叫笛卡尔积(cartesian product):由没有联结条件的表返回的结果为笛卡尔积,检索出的行的数目将是第一个表中的行数乘以第二表中的行数。

 (小知识:  叉联结(coss join):笛卡尔积的一种联结类型。)

      

如下图,一共有 6*14=84 行

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

 所以,应保证所有联结都有where 子句否则mysql 将返回比想要的数据多的多的数据,也要保证where 子句正确不然返回的也不对

如果你要调皮,就是不想用where 子句那么可以使用下面这种 内联结

 2、内部联结

等值联结(equijion):基于两个表之间的相等测试,也称为内部联结。就是一种特殊的语法实现上面的要求

关键字: inner join  , on

--  select 字段 from 表1 inner join 表2 on 表1.共有字段 = 表2.共有字段
 select vendors.vend_id,vendors.vend_name,products.prod_name from vendors inner join products on vendors.vend_id = products.vend_id order by vend_name;

 注意:ANSI SQL 规范首先 INNER JOIN(内部联结) 语法。因为这样专业,而且对性能有所提升,而且不能浪费一个语法 

方法有多种,那么你有没有想到,用之前学到的 where 子句进行实现呢?

是不觉得,就这,直接列出是不是不好呀,哎呀呀感觉有点长了,,,,,,,

 反正就是越复杂的sql 查询的效率就会相应的变慢,你觉得书写方便查询也会比较慢向 * ,like 语句,至于count(*) 感觉还好,貌似是mysql 有所优化。

3、联结多个表

SQL 对一条select 语句中可以联结的表的数目没有限制。而且,创建联结的基本规则也基本相同,先列出表然后定义表之间的关系

来个小例子

 用到的三个表

 将三个表联结起来  prodcuts 表就是中间粘合剂,注意sql 语法就行

 -- 查找这三个表中符合vendors.vend_id = products.vend_id and products.prod_id = orderitems.prod_id 条件的行
select vendors.vend_id,vend_name,products.prod_id,products.vend_id,orderitems.prod_id,orderitems.item_price from orderitems,products,vendors where vendors.vend_id = products.vend_id and products.prod_id = orderitems.prod_id order by vendors.vend_id;

 注意:mysql 在运行是关联指定的每个表以处理联结,这种处理是非常消耗资源的,所以不要联结过多的表,表越多性能下降越厉害

是不是你又想到了什么,之前的where 子查询的多表是不是也可以使用这里面的联结实现;

关于子查询的 https://i.cnblogs.com/posts/edit;postId=12972711

select cust_name,cust_contact from customers,orders,orderitems
   where customers.cust_id = orders.cust_id and orderitems.order_num = orders.order_num and prod_id = 'TNT2';

 注意: 

      1、完成一件事,不只有一个方法。

  2、很少有绝对正确或绝对错误的方法。社会是灰色的

  3、性能可能会受操作类型、表中数据量、是否存在索引、键以及其他一些条件方法

  4、建议可以对不同的选择机制进行实验,找出相对适合具体条件的方法,不怕困难才能顽强生长,长势良好

  5、联结是SQL 中最重要最强大的特性,想要随手写出优美的sql,还需要对关系性数据库设计有所了解

原文地址:https://www.cnblogs.com/obge/p/12979174.html