zoukankan      html  css  js  c++  java
  • mysql的查询、子查询及连接查询(商城查询常用)

    一、mysql查询的五种子句

            where(条件查询)、having(筛选)、group by(分组)、order by(排序)、limit(限制结果数)
     
    1、where常用运算符:
                比较运算符
                    > ,  < ,=  , != (< >),>=   ,   <=  
                    in(v1,v2..vn)  
    1. mysql> select id,name from user where id in(7,9,11,100);  
    2. +----+-----------+  
    3. | id | name      |  
    4. +----+-----------+  
    5. |  7 | 娲�紵楣?   |  
    6. |  9 | CCC       |  
    7. | 11 | 闄堥摥閽?   |  
    8. +----+-----------+  
    9. rows in set (0.02 sec)  


                    between v1 and v2    在v1至v2之间(包含v1,v2)
                逻辑运算符
                    not ( ! )  逻辑非
                    or ( || )    逻辑或
                    and ( && )  逻辑与
     
                    where price>=3000 and price <= 5000 or price >=500 and price <=1000 
                    取500-1000或者3000-5000的值
                    where price not between 3000 and 5000
                    不在3000与5000之间的值
     
                模糊查询
                    like 像
                    通配符:
                    %  任意字符
                    _   单个字符
                        where goods_name like '诺基亚%'
                        where goods_name like '诺基亚N__'     (必须要两个字符 ‘诺基亚N85’ ,诺基亚N9 就不行) 要匹配一个、两个字符的话不嫌麻烦的要OR把
     
    2、group by 分组
                 
    例子  aa表       a          b
                      123        10
                      123        12
                       1234       11
                       1234         14
    首先 group 是用来分组的  不是过滤重复项的。重复项删除语句 DISTINCT用这个 。 select  DISTINCT(a) from aa
    结果就是     a
                      123
                        1234
    
    group by用来分组的
    select a, sum(b) from aa group by a 
    sum意思是总和。结果就是
         a         b
        123      22
        1234    25
    语句的目的是以a为目标 需要知道 相同名字的物品   在b列一共有多少数量总和
    select a,count(b)  from aa group by a 
    count 意思行数总和   结果就是
          a         b
        123      2
        1234    2
    语句目的是  相同名字的物品 一共有几行
     
    (1)max:求最大值
                        select max(goods_price) from goods
                          这里会取出最大的价格的值,只有值
                            #查询每个栏目下价格最高的
                            select cat_id,max(goods_price) from goos group by cat_id;
                            #查出价格最高的商品编号
                            select goods_id,max(goods_price) from goods group by goods_id;
                            
                            
                    (2)min:求最小值
                    (3)sum:求总数和
                            #求商品库存总和
                            select sum(goods_number) from goods;
                    (4)avg:求平均值
                            #求每个栏目的商品平均价格
                            select cat_id,avg(goods_price) from goods group by cat_id;
                    (5)count:求总行数
                            #求每个栏目下商品种类
                            select cat_id,count(*) from goods group by cat_id;

    以ustuid为目标 统计apply表里每个ustuid有多少记录(用group by  结果有排序的效果(如下ustuid))

    1. mysql> select ustuid,count(*) from apply  group by ustuid;  
    2. +-----------+----------+  
    3. | ustuid    | count(*) |  
    4. +-----------+----------+  
    5. | 031302305 |        3 |  
    6. | 031302331 |       11 |  
    7. | 031302605 |        3 |  
    8. | 031302625 |        1 |  
    9. | 031302642 |        2 |  
    10. | 123123123 |        3 |  
    11. | 221300300 |        1 |  
    12. | 221300313 |        2 |  
    13. | 221300410 |        1 |  
    14. | 313       |        2 |  
    15. | 321321321 |        3 |  
    16. +-----------+----------+  
    17. 11 rows in set (0.09 sec)  



                       ###要把每个字段名当成变量来理解,它可以进行运算###
                            例:查询本店每个商品价格比市场价低多少;
                            select goods_id,goods_name,goods_price-market_price from goods;
                                查询每个栏目下面积压的货款
                            select cat_id,sum(goods_price*goods_number) from goods group by cat_id;
     
                        ###可以用as来给计算结果取个别名###
                            select cat_id,sum(goods_price * goods_number)  as hk from goods group by cat_id
                            不仅列名可以取别名,表单也可以取别名

     3、having 与where 的异同点
     
                        having与where类似,可以筛选数据,where后的表达式怎么写,having后就怎么写
                        where针对表中的列发挥作用,查询数据
                        having对查询结果中的列发挥作用,筛选数据
    1. mysql> select id,stuid,score as s from user;  
    2. +----+-----------+------+  
    3. | id | stuid     | s    |  
    4. +----+-----------+------+  
    5. |  5 | 031302331 |  111 |  
    6. |  7 | 221200420 |    0 |  
    7. |  8 | 221300300 |    0 |  
    8. |  9 | 031302305 |    8 |  
    9. | 11 | 031302605 |    7 |  
    10. | 12 | 313       |    0 |  
    11. | 13 | 031302625 |    0 |  
    12. | 14 | 221300313 |    0 |  
    13. | 15 | 031302642 |    0 |  
    14. | 17 | 031202303 |    0 |  
    15. | 19 | 221200238 |    0 |  
    16. | 20 | 221300410 |    0 |  
    17. | 21 | 123123123 |    0 |  
    18. | 22 | 321321321 |    0 |  
    19. +----+-----------+------+  
    20. 14 rows in set (0.00 sec)  

    感觉就像是score 换了一个名字 
     
    所以大概明白 having 就是把 前面一个表达式换了一个代号 有时候where 后面不能用 表达式的时候
     
                        //这里不能用where因为s是查询结果,而where只能对表中的字段名筛选
                        如果用where的话则是:
                        select goods_id,goods_name from goods where market_price - shop_price > 200;
     
                        #同时使用where与having
                        select cat_id,goods_name,market_price - shop_price as s from goods where cat_id = 3 having s > 200;
                        #查询积压货款超过2万元的栏目,以及该栏目积压的货款
                        select cat_id,sum(shop_price * goods_number) as t from goods group by cat_id having s > 20000
                        #查询两门及两门以上科目不及格的学生的平均分(stu表)
                              思路:
                                #先计算所有学生的平均分
                                 select name,avg(score) as pj from stu group by name;
                                #查出所有学生的挂科情况
                                select name,score<60 from stu;
                                        #这里score<60是判断语句,所以结果为真或假,mysql中真为1假为0
                                #查出两门及两门以上不及格的学生
                                select name,sum(score<60) as gk from stu group by name having gk > 1;
                                #综合结果
                                select name,sum(score<60) as gk,avg(score) as pj from stu group by name having gk >1;
     4、order by
                        (1) order by price  //默认升序排列
                        (2)order by price desc //降序排列
                        (3)order by price asc //升序排列,与默认一样
                        (4)order by rand() //随机排列,效率不高
                            #按栏目号升序排列,每个栏目下的商品价格降序排列
                            select * from goods where cat_id !=2 order by cat_id,price desc;
     如果是多个排序条件的 :
    1. mysql> select id,stuid,score from user order by score order by stuid;  
    2. ERROR 1064 (42000): You have an error in your SQL syntax; check the manual  
    3. mysql> select id,stuid,score from user order by score,stuid;  
    4. +----+-----------+-------+  
    5. | id | stuid     | score |  
    6. +----+-----------+-------+  
    7. | 17 | 031202303 |     0 |  
    8. | 13 | 031302625 |     0 |  
    9. | 15 | 031302642 |     0 |  
    10. | 21 | 123123123 |     0 |  
    11. | 19 | 221200238 |     0 |  
    12. |  7 | 221200420 |     0 |  
    13. |  8 | 221300300 |     0 |  
    14. | 14 | 221300313 |     0 |  
    15. | 20 | 221300410 |     0 |  
    16. | 12 | 313       |     0 |  
    17. | 22 | 321321321 |     0 |  
    18. | 11 | 031302605 |     7 |  
    19. |  9 | 031302305 |     8 |  
    20. |  5 | 031302331 |   111 |  
    21. +----+-----------+-------+  
    22. 14 rows in set (0.00 sec)  
    23.   
    24. mysql> select id,stuid,score from user order by stuid,score;  
    25. +----+-----------+-------+  
    26. | id | stuid     | score |  
    27. +----+-----------+-------+  
    28. | 17 | 031202303 |     0 |  
    29. |  9 | 031302305 |     8 |  
    30. |  5 | 031302331 |   111 |  
    31. | 11 | 031302605 |     7 |  
    32. | 13 | 031302625 |     0 |  
    33. | 15 | 031302642 |     0 |  
    34. | 21 | 123123123 |     0 |  
    35. | 19 | 221200238 |     0 |  
    36. |  7 | 221200420 |     0 |  
    37. |  8 | 221300300 |     0 |  
    38. | 14 | 221300313 |     0 |  
    39. | 20 | 221300410 |     0 |  
    40. | 12 | 313       |     0 |  
    41. | 22 | 321321321 |     0 |  
    42. +----+-----------+-------+  
    43. 14 rows in set (0.00 sec)  


                    5、limit
              
    在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了这样一个功能。
    SELECT * FROM table  LIMIT [offset,] rows | rows OFFSET offset


    LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1): 为了与 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #。 

    mysql> SELECT * FROM table LIMIT 5,10;  // 检索记录行 6-15

    //为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1: 
    mysql> SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.

    //如果只给定一个参数,它表示返回最大的记录行数目: 
    mysql> SELECT * FROM table LIMIT 5;     //检索前 5 个记录行

    //换句话说,LIMIT n 等价于 LIMIT 0,n。
                        
                ###查询每个栏目下最贵的商品
                    思路:
                            #先对每个栏目下的商品价格排序
                            select cat_id,goods_id,goods_name,shop_price from goods order by cat_id,shop_price desc;
                            #上面的查询结果中每个栏目的第一行的商品就是最贵的商品
                            #把上面的查询结果理解为一个临时表[存在于内存中]【子查询】
                            #再从临时表中选出每个栏目最贵的商品
                            select * from (select goods_id,goods_name,cat_id,shop_price from goods order by cat_id,shop_price desc) as t group by cat_id;             as t 作为临时表 这个语句不能缺
                            #这里使用group by cat_id是因为临时表中每个栏目的第一个商品就是最贵的商品,而group by前面没有使用聚合函数,所以默认就取每个分组的第一行数据,这里以cat_id分组
     
                     良好的理解模型:
                        1、where后面的表达式,把表达式放在每一行中,看是否成立
                        2、字段(列),理解为变量,可以进行运算(算术运算和逻辑运算)  
                        3、 取出结果可以理解成一张临时表
     二、mysql子查询
            1、where型子查询
                    (把内层查询结果当作外层查询的比较条件)
                    #不用order by 来查询最新的商品
                    select goods_id,goods_name from goods where goods_id = (select max(goods_id) from goods);
                    #取出每个栏目下最新的产品(goods_id唯一)
                    select cat_id,goods_id,goods_name from goods where goods_id in( select max(goods_id) from goods group by cat_id);
     
            2、from型子查询
                    (把内层的查询结果供外层再次查询)
                    #用子查询查出挂科两门及以上的同学的平均成绩
                        思路:
                            #先查出哪些同学挂科两门以上
                            select name,count(*) as gk from stu where score < 60 having gk >=2;
                            #以上查询结果,我们只要名字就可以了,所以再取一次名字
                            select name from (select name,count(*) as gk from stu having gk >=2) as t;
                            #找出这些同学了,那么再计算他们的平均分
                            select name,avg(score) from stu where name in (select name from (select name,count(*) as gk from stu having gk >=2) as t) group by name;
     
            3、exists型子查询
                    (把外层查询结果拿到内层,看内层的查询是否成立)
                    #查询哪些栏目下有商品,栏目表category,商品表goods
                        select cat_id,cat_name from category where exists(select * from goods where goods.cat_id = category.cat_id);

    查询 哪些 用户(user)有 申请记录(apply)

    注:可以用【 表名.字段名】来表示

    如下面的sql语句也可以这样下

    1. mysql> select id,stuid,name from user where exists(select * from apply where apply.ustuid =user.stuid);  


    1. mysql> select id,stuid,name from user where exists(select * from apply where ustuid =stuid);  
    2. +----+-----------+-----------+  
    3. | id | stuid     | name      |  
    4. +----+-----------+-----------+  
    5. |  5 | 031302331 | 閮戝�鍏?   |  
    6. |  8 | 221300300 | 鏋?       |  
    7. |  9 | 031302305 | CCC       |  
    8. | 11 | 031302605 | 闄堥摥閽?   |  
    9. | 12 | 313       | 钀у畤      |  
    10. | 13 | 031302625 | 鍚村厛婊?   |  
    11. | 14 | 221300313 | 钀у畤      |  
    12. | 15 | 031302642 | 鍚撮敠绉?   |  
    13. | 20 | 221300410 | 鏉庣懚姹?   |  
    14. | 21 | 123123123 | zjx       |  
    15. | 22 | 321321321 | 123123    |  
    16. +----+-----------+-----------+  
    17. 11 rows in set (0.02 sec)  
     三、union的用法

    UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。

    举例说明:

    1. select * from table1 union select * from table2    

    这个SQL在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。  

    MySQL中的UNION ALL
    UNION ALL只是简单的将两个结果合并后就返回。这样,如果返回的两个结果集中有重复的数据,那么返回的结果集就会包含重复的数据了。

    举例说明:

    1. select * from table1 union all select * from table2    

    注: 使用 UNION 时 前一个 select column的个数要等于后一个select column的个数
    如:
    1. table1: (id,createDate,lastUpdateDate,desc,num,hashCode),    
    2. table2: (id,createDate,lastUpdateDate,desc)    


    如果现在使用:

    1. select * from table1 UNION ALL select * from table2    


    则是不会成功的, 数据库为报: 

    Error
    The used SELECT statements have a different number of columns

    这是提示查询的两张表的字段不统一,如果table1比table2的字段内容多,可以使用空字符串来代替

    1. select id,createDate,lastUpdateDate,desc,num,hashCode from table1 UNION ALL select id,createDate,lastUpdateDate,desc,'','' from table2  


    如果里面有不想要的,千万要记住前面查询内容要和后面查询内容的字段个数要一样,前面你查询4个,后面也要相应的放4个,这样就不会提示参数数量不同的错误了。

    其实稍稍修改一下就可以了
    对于 'select id,createDate,desc,hasCode from table1' 可以任意选择4个field

    从效率上说,UNION ALL 要比UNION快很多,所以,如果可以确认合并的两个结果集中不包含重复的数据的话,那么就使用UNION ALL。

    如果遇到两张表数据不同来集合查询,可以使用union all这个函数进行操作

    1. SELECT COUNT(c.a)  FROM (  
    2. (SELECT UID a,ID,SERIAL,ParkName,CardNO,ScoreRealPay,PayFlag,PayType,Createtime FROM cp_consumption_record WHERE UID=761 AND PayFlag=1  ORDER BY Createtime DESC) UNION ALL (SELECT UID a,CpResID,CpParkID,ParkSERIAL,CarCode,Price,BusinessType,CardNO,CreateDate FROM cp_reservation WHERE UID=761 AND BusinessType IN(1,2,3) ORDER BY CreateDate DESC)  
    3. ) c  

    这是查询结果集共有多少条数据,

    如果还有查询条件,直接在c后面添加就可以,比如按照时间进行查询

    1. SELECT c.UID,c.ScoreRealPay,c.PayFlag,c.PayType  FROM (  
    2. (SELECT UID AS UID,ID AS ID,SERIAL AS SERIAL ,ParkName AS ParkName,CardNO CardNO,ScoreRealPay ScoreRealPay,PayFlag PayFlag,PayType PayType,Createtime Createtime FROM cp_consumption_record WHERE UID=761 AND PayFlag=1  ORDER BY Createtime DESC) UNION ALL (SELECT UID a,CpResID,CpParkID,ParkSERIAL,CarCode,Price,BusinessType,CardNO,CreateDate FROM cp_reservation WHERE UID=761 AND BusinessType IN(1,2,3) ORDER BY CreateDate DESC)  
    3. ) c ORDER BY Createtime DESC/ASC  

    这里强调一下,你要按照什么样的条件进行查询时,要分别在select子查询中添加上条件,最后在按照统一的时间倒序或者正序

    注: 
    缺省的情况下,UNION 子句不返回重复的记录.如果想显示所有记录,可以加ALL选项 
    UNION运算要求查询具有相同数目的字段.但是,字段数据类型不必相同. 

    四、左连接,右连接,内连接

     现有表a有10条数据,表b有8条数据,那么表a与表b的笛尔卡积是多少?
                        select * from ta,tb   //输出结果为8*10=80条
                      
                1、左连接
                   以左表为准,去右表找数据,如果没有匹配的数据,则以null补空位,所以输出结果数>=左表原数据数
     
                    语法:select n1,n2,n3 from ta left join tb on ta.n1= ta.n2 [这里on后面的表达式,不一定为=,也可以>,<等算术、逻辑运算符]【连接完成后,可以当成一张新表来看待,运用where等查询
              下面是例子分析
    表A记录如下: 
    aID        aNum 
    1           a20050111 
    2           a20050112 
    3           a20050113 
    4           a20050114 
    5           a20050115 

    表B记录如下: 
    bID        bName 
    1            2006032401 
    2           2006032402 
    3           2006032403 
    4           2006032404 
    8           2006032408 

    创建这两个表SQL语句如下: 
    CREATE TABLE  a 
    aID int( 1 ) AUTO_INCREMENT PRIMARY KEY , 
    aNum char( 20 ) 

    CREATE TABLE b( 
    bID int( 1 ) NOT NULL AUTO_INCREMENT PRIMARY KEY , 
    bName char( 20 )  


    INSERT INTO a 
    VALUES ( 1, 'a20050111' ) , ( 2, 'a20050112' ) , ( 3, 'a20050113' ) , ( 4, 'a20050114' ) , ( 5, 'a20050115' ) ; 

    INSERT INTO b 
    VALUES ( 1, ' 2006032401' ) , ( 2, '2006032402' ) , ( 3, '2006032403' ) , ( 4, '2006032404' ) , ( 8, '2006032408' ) ; 

    实验如下: 
    1.left join(左联接) 

    sql语句如下:  
    SELECT * FROM a 
    LEFT JOIN  b  
    ON a.aID =b.bID 

    结果如下: 
    aID        aNum                   bID           bName 
    1            a20050111         1               2006032401 
    2            a20050112         2              2006032402 
    3            a20050113         3              2006032403 
    4            a20050114         4              2006032404 
    5            a20050115         NULL       NULL 
    (所影响的行数为 5 行) 

    结果说明: 
            left join是以A表的记录为基础的,A可以看成左表,B可以看成右表,left join是以左表为准的. 
    换句话说,左表(A)的记录将会全部表示出来,而右表(B)只会显示符合搜索条件的记录(例子中为: A.aID = B.bID). 
    B表记录不足的地方均为NULL. 
               2、右连接
                    a left join b 等价于 b right join a
                    推荐使用左连接代替右连接
                    语法:select n1,n2,n3 from ta right join tb on ta.n1= ta.n2
    3.inner join(相等联接或内联接) 

    sql语句如下:  
    SELECT * FROM  a 
    INNER JOIN  b 
    ON a.aID =b.bID 

    等同于以下SQL句: 
    SELECT *  
    FROM a,b 
    WHERE a.aID = b.bID 

    结果如下: 
    aID        aNum                   bID           bName 
    1            a20050111         1               2006032401 
    2            a20050112         2              2006032402 
    3            a20050113         3              2006032403 
    4            a20050114         4              2006032404 

    结果说明: 
            很明显,这里只显示出了 A.aID = B.bID的记录.这说明inner join并不以谁为基础,它只显示符合条件的记录. 
    LEFT JOIN操作用于在任何的 FROM 子句中, 

    组合来源表的记录。使用 LEFT JOIN 运算来创建一个左边外部联接。左边外部联接将包含了从第一个(左边)开始的两个表中的全部记录,即 
    使在第二个(右边)表中并没有相符值的记录。  

    语法:FROM table1 LEFT JOIN table2 ON table1.field1 compopr table2.field2  
    说明:table1, table2参数用于指定要将记录组合的表的名称。 
    field1, field2参数指定被联接的字段的名称。且这些字段必须有相同的数据类型及包含相同类型的数据,但它们不需要有相同的 
    名称。 
    compopr参数指定关系比较运算符:"=", "<", ">", "<=", ">=" 或 "<>"。 
    如果在INNER JOIN操作中要联接包含Memo 数据类型或 OLE Object 数据类型数据的字段,将会发生错误。
  • 相关阅读:
    1014 Waiting in Line (30)(30 point(s))
    1013 Battle Over Cities (25)(25 point(s))
    1012 The Best Rank (25)(25 point(s))
    1011 World Cup Betting (20)(20 point(s))
    1010 Radix (25)(25 point(s))
    1009 Product of Polynomials (25)(25 point(s))
    1008 Elevator (20)(20 point(s))
    1007 Maximum Subsequence Sum (25)(25 point(s))
    1006 Sign In and Sign Out (25)(25 point(s))
    1005 Spell It Right (20)(20 point(s))
  • 原文地址:https://www.cnblogs.com/zhangzhaoyang/p/7741167.html
Copyright © 2011-2022 走看看