zoukankan      html  css  js  c++  java
  • mysql连表查询

    学习连接查询,先了解下"笛卡尔积",看下百度给出的解释:

     

         在数据库中,一张表就是一个集合,每一行就是集合中的一个元素。表之间作联合查询即是作笛卡尔乘积,比如A表有5条数据,B表有8条数据,如果不作条件筛选,那么两表查询就有5 X 8 = 40 条数据。

    先看下用到的测试表基本信息:我们要实现的功能就是查询商品的时候,从类别表将商品类别名称关联查询出来。

    行数:类别表14条,商品表4条。

     

    结构:商品表和类别表都有一个cat_id

     

    1、全相乘(不是全连接、连接查询),全相乘是作笛卡尔积

    两表全相乘,就是直接从两张表里查询;从查询的截图看出,总共查出了4 X 14 = 56 条记录,这些记录是笛卡尔乘积的结果,即两两组合;

    但我们要的是每个商品信息显示类别名称而已,这里却查出了56条记录,其中有52条记录都是无效的数据,全相乘的查询效率低

    SELECT goods_id,goods_name,cat_name FROM mingoods,category;

     

    如果在两张表里有相同字段,做联合查询的时候,要区别表名,否则会报错误(模糊不清)。

    SELECT goods_name,cat_id,cat_name FROM mingoods,category; 

     

          添加条件,使两表关联查询,这样查出来就是商品和类别一一对应了。虽然这里查出来4条记录,但是全相乘效率低,全相乘会在内存中生成一个非常大的数据(临时表),因为有很多不必要的数据。

        如果一张表有10000条数据,另一张表有10000条数据,两表全相乘就是100W条数据,是非常消耗内存的。而且,全相乘不能好好的利用索引,因为全相乘生成一张临时表,临时表里是没有索引的,大大降低了查询效率。

    SELECT g.goods_name,g.cat_id AS g_cat_id, c.cat_id AS c_cat_id, c.cat_name FROM mingoods g, category c WHERE g.cat_id = c.cat_id;

     

    2、左连接查询left join ... on ...

    语法:

    select A.filed, [A.filed2, .... ,] B.filed, [B.filed4...,]from<lefttable>as A  leftjoin<righttable>as B on<expression>

    假设有A、B两张表,左连接查询即A表在左不动,B表在右滑动,A表与B表通过一个关系来关联行,B表去匹配A表。

    2.1、先来看看on后的条件恒为真的情况

    SELECT g.goods_name,g.cat_id, c.cat_id ,c.cat_name FROM mingoods g LEFTJOIN category c ON1;

        跟全相乘相比,从截图可以看出,总记录数仍然不变,还是4 X 14 = 56 条记录。但这次是商品表不动,类别表去匹配,因为每次都为真,所以将所有的记录都查出来了。左连接,其实就可以看成左表是主表,右表是从表。

     

    2.2 、根据cat_id使两表关联行

    SELECT g.goods_name,g.cat_id,c.cat_id,c.cat_name FROM mingoods g LEFTJOIN category c ON g.cat_id = c.cat_id;

    使用左连接查询达到了同样的效果,但是不会有其它冗余数据,查询速度快,消耗内存小,而且使用了索引。左连接查询效率相比于全相乘的查询效率快了10+倍以上。

      左连接时,mingoods表(左表)不动,category表(右表)根据条件去一条条匹配,虽说category表也是读取一行行记录,然后判断cat_id是否跟mingoods表的相同,但是,左连接使用了索引,cat_id建立了索引的话,查询速度非常快,所以整体效率相比于全相乘要快得多,全相乘没有使用索引。

     

    2.3、查询出第四个类别下的商品,要求显示商品名称

    SELECT g.goods_name,g.cat_id,c.cat_name,g.shop_price FROM goods g LEFTJOIN category c ON g.cat_id = c.cat_id WHERE g.cat_id =4;

     

    2.4 、对于左连接查询,如果右表中没有满足条件的行,则默认填充NULL

    SELECT g.goods_name,g.cat_id AS g_cat_id, c.cat_id AS c_cat_id,c.cat_id FROM mingoods g LEFTJOIN mincategory c ON g.cat_id = c.cat_id;

     

    3、右连接查询right join ... on ...

    语法:

    select A.field1,A.field2,..., B.field3,B.field4  from<lefttable> A rightjoin<righttable> B on<expression>

    右连接查询跟左连接查询类似,只是右连接是以右表为主表,会将右表所有数据查询出来,而左表则根据条件去匹配,如果左表没有满足条件的行,则左边默认显示NULL。左右连接是可以互换的。

    SELECT g.goods_name,g.cat_id AS g_cat_id,  c.cat_id AS c_cat_id,c.cat_name FROM mingoods g RIGHTJOIN mincategory c ON g.cat_id = c.cat_id;

     

    4、内连接查询inner join ... on ...

    语法:

    select A.field1,A.field2,.., B.field3, B.field4 from<lefttable> A innerjoin<righttable> B on<expression>

    内连接查询,就是取左连接和右连接的交集,如果两边不能匹配条件,则都不取出。

    SELECT g.goods_name,g.cat_id, c.*from mingoods g INNERJOIN mincategory c ON g.cat_id = c.cat_id;

     

    5、全连接查询full join ... on ...

    语法:

    select ... from<lefttable>fulljoin<righttable>on<expression>

    全连接会将两个表的所有数据查询出来,不满足条件的为NULL。

    全连接查询跟全相乘查询的区别在于,如果某个项不匹配,全相乘不会查出来,全连接会查出来,而连接的另一边则为NULL。

    6、联合查询union

    语法:

    select A.field1 as f1, A.field2 as f2 from<table1> A union (select B.field3 as f1, field4 as f2 from<table2> B)

    union是求两个查询的并集。union合并的是结果集,不区分来自于哪一张表,所以可以合并多张表查询出来的数据。

     

    6.1、将两张表的数据合并查询出来

    SELECT id, content, userFROM comment UNION (SELECT id, msg AS content, userFROM feedback);

     

    6.2union查询,列名不一致时,以第一条sql语句的列名对齐

    SELECT id, content, userFROM comment UNION (SELECT id, msg, userFROM feedback);

     

    6.3、使用union查询会将重复的行过滤掉

    SELECT content,userFROM comment UNION (SELECT msg, userFROM feedback);

     

    6.4、使用union all查询所有,重复的行不会被过滤

    SELECT content,userFROM comment UNIONALL (SELECT msg, userFROM feedback);

     

    6.5union查询,如果列数不相等,会报列数不相等错误

     

    6.6union 后的结果集还可以再做筛选

    SELECT id,content,userFROM comment UNIONALL (SELECT id, msg, userFROM feedback) ORDERBY id DESC; 

     

       union查询时,order by放在内层sql中是不起作用的;因为union查出来的结果集再排序,内层的排序就没有意义了;因此,内层的order by排序,在执行期间,被mysql的代码分析器给优化掉了。

    (SELECT id,content,userFROM comment ORDERBY id DESC) UNIONALL (SELECT id, msg, userFROM feedback ORDERBY id DESC);

     

    order by 如果和limit一起使用,就显得有意义了,就不会被优化掉。

    ( SELECT goods_name,cat_id,shop_price FROM goods WHERE cat_id =3ORDERBY shop_price DESC LIMIT 3 )
    UNION
    ( SELECT goods_name,cat_id,shop_price FROM goods WHERE cat_id =4ORDERBY shop_price DESC LIMIT 2 );

     

     6.7、练习

    SELECT name, SUM(money) FROM ( ( SELECT*FROM A ) UNIONALL ( SELECT*FROM B ) ) tmp GROUPBY name;

     

     

    连接查询总结:

    1、在数据库中,一张表就是一个集合,每一行就是集合中的一个元素。连接查询即是作笛卡尔积,比如A表有1W条数据,B表有1W条数据,那么两表查询就有1W X 1W = 100W 条数据 

    2、如果在两张表里有相同字段,做联合查询的时候,要区别表名,否则会报错误(ambiguous 模糊不清)

    3、全相乘效率低,全相乘会在内存中生成一个非常大的数据(临时表),因为有很多不必要的数据。

     如果一张表有10000条数据,另一张表有10000条数据,两表全相乘就是100W条数据,是非常消耗内存的。

    而且,全相乘不能好好的利用索引,因为全相乘生成一张临时表,临时表里是没有索引的,大大降低了查询效率。

    4、左连接查询时,以左表为主表,会将左表所有数据查询出来;左表不动,右表根据条件去一条条匹配,如果没有满足条件的记录,则右边返回NULL。

    右连接查询值,以右表为主表,会将右表所有数据查询出来,右表不动,左表则根据条件去匹配,如果左表没有满足条件的行,则左边返回NULL。 

    左右连接是可以互换的:A left join B  ==  B right join A (都是以A为主表) 。

    左右连接既然可以互换,出于移植兼容性方面的考虑,尽量使用左连接。

    5、连接查询时,虽说也是读取一行行记录,然后判断是否满足条件,但是,连接查询使用了索引,条件列建立了索引的话,查询速度非常快,所以整体效率相比于全相乘要快得多,全相乘是没有使用索引的。

    使用连接查询,查询速度快,消耗内存小,而且使用了索引。连接查询效率相比于全相乘的查询效率快了10+倍以上。

    6、内连接查询,就是取左连接和右连接的交集,如果两边不能匹配条件,则都不取出。

    7、MySql可以用union(联合查询)来查出左连接和右连接的并集

    union查询会过滤重复的行,union all 不会过滤重复的行。

    union查询时,union之间的sql列数必须相等,列名以第一条sql的列为准;列类型可以不一样,但没太大意义。

    union查询时,order by放在内层sql中是不起作用的;因为union查出来的结果集再排序,内层的排序就没有意义了;因此,内层的order by排序,在执行期间,被mysql的代码分析器给优化掉了。

     但是,order by 如果和limit一起使用,就显得有意义了,会影响最终结果集,就不会被优化掉。order by会根据最终是否会影响结果集而选择性的优化。

    注:union和union all的区别,union会去掉重复的记录,在结果集合并后悔对新产生的结果集进行排序运算,效率稍低,union all直接合并结果集,如果确定没有重复记录,建议使用union all。

    8、LEFT JOIN 是LEFT OUTER JOIN 的缩写,同理,RIGHT JOIN 是RIGHT OUTER JOIN 的缩写;JOIN 是INNER JOIN 的缩写。


    关联查询

    1、使用join关键字关联查询

    1)、内连接(inner join

    连接两张表,连接条件使用on关键字,内连接只会显示匹配的数据记录。

    eg:查询学生姓名、科目、分数

    select a.name 姓名,b.subject 科目,b.score 分数from student a innerjoin score b on a.id = b.sid;

     

    2)、左连接(left join

    返回左表中所有记录以及右表中符合连接条件的所有记录。

    eg: 使用左连接查询学生姓名、科目、分数

    select a.name 姓名,b.subject 科目,b.score 分数from student a leftjoin score b on a.id = b.sid;

     

    3)、右连接(right join

    返回右表中所有记录以及左表中符合连接条件的所有记录。

    eg:使用右连接查询学生姓名、科目、分数

    select a.name 姓名,b.subject 科目,b.score 分数from student a rightjoin score b on a.id = b.sid;

     

    注:内外连接区别:内连接只会显示匹配的数据记录,外连接例如左连接会把左边表中所有记录显示出来,即使在右边表中没有匹配记录也会显示左表的数据,右连接反之。

    2、使用表和表之间相同id关联查询

    这种关联方式和内连接一样,只会显示出匹配的数据

    select a.name 姓名,b.subject 科目,b.score 分数from student a,score b where a.id = b.sid;
  • 相关阅读:
    717 汉诺塔的非递归实现 (25分)
    JSP入门[续]
    JSP运行原理和九大隐式对象
    JSP入门
    Mysql基本命令
    DataGridView数据导出为Excel
    sql server 2005中如何添加外键
    自定义配置文件的读取
    WinForm(C#)CheckedlistBox绑定数据,并获得选中的值(ValueMember)和显示文本(DisplayMember
    No CurrentSessionContext configured Hibernate
  • 原文地址:https://www.cnblogs.com/ting152/p/12454047.html
Copyright © 2011-2022 走看看