MySQL学习之单表查询

眉间皱痕 提交于 2019-12-17 01:21:44

语法

语法:
SELECT distinct 字段1, 字段2... FROM 表名
                               WHERE 条件
                               GROUP BY field
                               HAVING 筛选
                               ORDER BY field
                               LIMIT 限制条数;

优先级

优先级:
    from
    where
    group by
    having
    select
    distinct
    order by
    limit
1. 找到表:from

2. 拿着where指定的约束条件,去文件/表中取出一条条记录

3. 将取出的一条条记录进行分组group by,如果没有group by,则整体作为一组

4. 将分组的结果进行having过滤

5. 执行select

6. distinct去重

7. 将结果按条件排序:order by

8. limit限制结果的显示条数

distinct

# DISTINCT: 放在字段的前面,对其后所有的字段都生效,记录重复的只显示一次(记录去重)
# distinct 效率不高,如果能用其他方式实现,首选其他
    # =============================================================
        MySQL DISTINCT 的作用:
            排除重复的行
            (根据参数所指定的列排除重复的行)

        DISTINCT 有带括号和没括号的两种用法,这两种是如何指定参数的呢 ?
        我们使用过程中发现

        1. 如果跟其它函数结合使用,那么只会使用小括号内的参数
        2. 否则,那么 DISTINCT 关键字后的所有列都是参数

        MySQL DISTINCT 的位置:
        千万不要认为 DISTINCT 只能放在开头,也不要认为 DISTINCT 可以放在任意位置。

        1. 单独的 DISTINCT 关键字只能放在开头,放在其它位置会报错

        2. 如果是配合其它的函数使用,比如 COUNT(), 应该是其它函数可以任意位置时,DISTINCT 也可以任意位置

        DISTINCT 中的小括号 ():
            SQL 解析器会忽略 DISTINCT 关键字后面的小括号,而把 DISTINCT 关键字后面的所有列都作为唯一条件

        SQL DISTINCT 的基本用法:
            在日常使用 DISTINCT 关键字时,一般有以下几种
                ###注意: 请留意每种的列的数量###

            1. 单独获取某一列不重复的值
                这种情况下,有无小括号的结果是一样的
                SELECT DISTINCT user FROM fruits;
                SELECT DISTINCT(user) FROM fruits;

            2. 单独获取某一列不重复值的数量
                SELECT COUNT(DISTINCT(user)) FROM fruits;

            3. 以多列作为条件获取不同的值
                一定要记住,当你使用多列时,并不仅仅时使用小括号内的列,而是全部列
                SELECT DISTINCT(user),fruit FROM fruits;
    # ============================================================

where子句

# where子句:
    # =======================================================================
       WHERE 子句要在 FROM 子句之后给出
       文本字段 vs 数值字段
           1. SQL 使用单引号来环绕文本值
              虽然大部分数据库系统也接受双引号,但我们极力反对使用双引号

           2. 如果是数值字段,请不要使用引号
              虽然使用数值字段也可以使用单引号,但数据库系统要经过一次数据类型转换,增加了数据库系统的开销

        # where子句中的运算符:
            运算符	            描述
            =	                等于
            <>	                不等于
            >	                大于
            <	                小于
            >=	                大于等于
            <=	                小于等于
            BETWEEN	            在某个范围内
            LIKE	            搜索某种模式
            IN	                指定针对某个列的多个可能值

            ##  在 SQL 的一些版本中,<>操作符可被写成 !=  ##

        # > / >= / < / <= / != / <> / = / <=> (<=>是MYSQL特有的)
                安全等于<=>
                1.可作为普通运算符的=
                2.也可以用于判断是否是NULL 如:where salary is NULL/(is not NULL) ->where salary <=> NULL

        # between ... and ... / not between .... and ....
            # =====================================================================
                SQL BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期
                注意

                不同的数据库中,BETWEEN 操作符会产生不同的结果

                在某些数据库中,BETWEEN 选取介于两个值之间但不包括两个测试值的字段
                在某些数据库中,BETWEEN 选取介于两个值之间且包括两个测试值的字段   -----> MySQL属于这种
                在某些数据库中,BETWEEN 选取介于两个值之间且包括第一个测试值但不包括最后一个测试值的字段
                因此,请检查你的数据库系统是如何处理 BETWEEN 操作符

                例子:
                    1. 选取 id 介于 13 之间的所有课程
                        SELECT * FROM lesson WHERE id BETWEEN 1 AND 3;
                    2. 选取 id 不在 13 之间的所有课程
                        SELECT * FROM lesson WHERE id NOT BETWEEN 1 AND 3;VARCHAR 等文本类型上使用 BETWEEN 操作符
                    1. 选取 name 以介于 'O''S' 之间字母开始的所有课程
                        SELECT * FROM lesson WHERE name BETWEEN 'O' AND 'S';
                    2. 选取 name 不介于 'O''S' 之间字母开始的所有课程
                        SELECT * FROM lesson WHERE name NOT BETWEEN 'O' AND 'S';DATETIME 等日期类型列上使用 BETWEEN 操作符
                    1. 选取 created_at 介于 2017-04-18 16:03:322017-05-01 06:16:14 之间的数据
                        SELECT * FROM lesson WHERE created_at BETWEEN '2017-04-18 16:03:32' AND '2017-05-01 06:16:14';

                最佳实战:
                一般情况下,我们不推荐使用 BETWEEN
                为什么呢?
                    因为 BETWEEN 并不是所有开发者都熟悉,而且不同数据库实现有不一样的实现
                那我们可以用什么代替呢?
                    我们可以用 >< 代替,比如下面的 SQL 语句选取 id 介于 13 之间的所有课程
                    SELECT * FROM lesson WHERE id >=1 AND id <=3;
            # ==========================================================================

        # not > and > or

        # in / not in
            # =========================================================
                SQL IN 操作符用于在 WHERE 子句中限制一列只能包含有限个值
                例如:
                    SELECT * FROM lesson WHERE id IN (1,3);

                    where id in (select id from t11);
            # ===========================================================

        # is / is not null (判断某个字段是否为NULL,不能用等号,需要用IS)

        # like / not like

        # rlike / not rlike

        # regexp / not regexp
    # =============================================================================

like子句

# like子句:
    # =====================================================================
        SQL 中的 LIKE 子句用于在 WHERE 子句中搜索列中的指定模式
            SELECT column_name(s) FROM table_name WHERE column_name LIKE pattern;
        pattern 是一个合法的模式字符串,有很多种 模式,但最常用的也是最容易记住的就是百分号 ( % ) 可以代替任意字符

        SQL LIKE 操作符:
        1. 如果我们不使用任何通配符,那么 LIKE 的效果相当于 = 操作符
            SELECT * FROM lession WHERE name LIKE 'Python 基础教程';

        2. 因为百分号 ( % ) 可以代替任何任意数量的字符,所以下面的 SQL 语句选取 name 以 S 开头的课程
            SELECT * FROM lession WHERE name LIKE 'S%';

        3. 下面的 SQL 语句选取 name 以字符串 "教程" 结尾的所有课程
            SELECT * FROM lession WHERE name LIKE '%教程';

        4. 下面的 SQL 语句选取 name 包含 y 字母的课程
            SELECT * FROM lession WHERE name LIKE '%y%';

        5. 通过使用 NOT 关键字,我们可以选取不匹配模式的记录
            下面的 SQL 语句选取 name 不包含 "y" 的所有课程
                SELECT * FROM lession WHERE name NOT LIKE '%y%';
    # =====================================================================

通配符

```sql
# 通配符: 特别注意(默认情况下, windows下的MySQL什么都不分大小写, 包括, 查询参数)
    # ======================================================================
        SQL 通配符:
            SQL 中,通配符与 SQL LIKE 操作符一起使用,可用于替代字符串中的任何其他字符

            SQL 中规定可以使用以下通配符:

            通配符	                    描述
            %	                        替代 0 个或多个字符
            _	                        替代一个字符
            [charlist]	                字符列中的任何单一字符
            [^charlist][!charlist]	不在字符列中的任何单一字符

        使用 SQL % 通配符:
            SELECT * FROM lession WHERE name LIKE 'S%';

        使用 SQL _ 通配符:
            选取 name 以一个任意字符开始,然后是 "ython" 的所有课程
                SELECT * FROM lession WHERE name LIKE '_ython%';

            选取 name 以 "S" 开始,然后是一个任意字符,然后是 "a",然后是一个任意字符,然后是 "a" 的所有课程
                SELECT * FROM lession WHERE name LIKE 'S_a_a%';

        使用 SQL [charlist] 通配符:
            MySQL 中使用 REGEXPNOT REGEXP 运算符 (RLIKENOT RLIKE) 来操作正则表达式
                1. 选取 name 以 "P""S" 开始的课程
                    SELECT * FROM lession WHERE name REGEXP '^[PS]';

            # 使用正则进行查询:
                SELECT * FROM employee WHERE name REGEXP '^ale';

                SELECT * FROM employee WHERE name REGEXP 'on$';

                SELECT * FROM employee WHERE name REGEXP 'm{2}';

        其它:
        # where name like 'a%'  # 以a开头的字符串,%代表0个或者多个字符
        # where name like 'a_'  # _代表一个字符
        # 使用通配符进行检索是很慢的,如果能用其他操作符达到相同的效果,应该首选操作符;
        # 并且不要把通配符放在模式的第一个,这样做的话,效率很低

        # 特别的:
        如果字段是整型,也能使用like
    # =======================================================================

group by子句

# group by 子句:
    # =======================================================================================================
        # 分组指的是:将所有记录按照某个相同字段进行归类,比如针对员工信息表的职位分组,或者按照性别进行分组等
        # 小窍门:‘每’这个字后面的字段,就是我们分组的依据
        # 提醒:
              可以按照任意字段分组,但是分组完毕后,比如group by post,只能查看post字段,
              如果想查看组内信息,需要借助于聚合函数

        ##############################################################################################

        1. 查看MySQL 5.7默认的sql_mode
           select @@global.sql_mode;


           在ONLY_FULL_GROUP_BY模式下,
           target list中的值要么是来自于聚集函数的结果,
           要么是来自于group by list中的表达式的值。

        #设置sql_mole如下操作(我们可以去掉ONLY_FULL_GROUP_BY模式):
        set global sql_mode='STRICT_TRANS_TABLES,
                            NO_ZERO_IN_DATE,
                            NO_ZERO_DATE,
                            ERROR_FOR_DIVISION_BY_ZERO,
                            NO_AUTO_CREATE_USER,
                            NO_ENGINE_SUBSTITUTION';

        执行select * from employee group by post;
        #由于没有设置ONLY_FULL_GROUP_BY,于是也可以有结果,默认都是组内的第一条记录,但其实这是没有意义的

        set global sql_mode='ONLY_FULL_GROUP_BY';
        #设置成功后,一定要退出,然后重新登录方可生效

        #######################################################################################################

        范例:
            统计各个课程的总访问量
               SELECT lesson_name, SUM(views) FROM lesson_views GROUP BY lesson_name;

                GROUP BY X, Y意思是将所有具有相同X字段值和Y字段值的记录放到一个分组里。

        SQL GROUP BY 多表连接
            SELECT lesson.name,SUM(lesson_views.views)
                FROM lesson,lesson_views
                WHERE lesson.id=lesson_views.lesson_id
                GROUP BY lesson.name;


        ############################################

        强调:
        (在单表下)如果我们用unique的字段作为分组的依据,则每一条记录自成一组,这种分组没有意义
        多条记录之间的某个字段值相同,该字段通常用来作为分组的依据

        ##############################################
        # select num from t11 group by num;  根据num把相同的聚合为一组, 分组就是分类

        # GROUP BY关键字和GROUP_CONCAT()函数一起使用
        # 将一组中的字段值, 拼接在一起显示出来.
        SELECT post,GROUP_CONCAT(name) as emp_members FROM employee GROUP BY post;

        # ===================================================================================

having子句

# having 子句:
    # ================================================================================
        SQL 中的 HAVING 子句用于筛选分组 ( GROUP BY ) 后的各组数据,相当于 SELECT 语句中的 WHERE 语句

        HAVING 子句一般跟在 GROUP BY 子句后面

        可以看作是where做了第一次筛选,having进行第二次筛选

        SQL HAVING 范例:
            选择总访问量在 100 以内的课程
            SELECT lesson_name, SUM(views) as total_views
                FROM lesson_views
                GROUP BY lesson_name
                HAVING total_views < 100;   # 别名

            又学习了:

            select lesson_name, sum(views) as total_views
                from lesson_views
                group by lesson_name
                having sum(views) < 100;
        #####################################################################################
        HAVINGWHERE不一样的地方在于!!!!!!

        #!!!执行优先级从高到低:where > group by > having
        #1. Where 发生在分组group by之前,因而Where中可以有任意字段,但是绝对不能使用聚合函数。

        #2. Having发生在分组group by之后,因而Having中可以使用分组的字段,无法直接取到其他字段,可以使用聚合函数

        可以看作where做了第一次筛选,having进行第二次筛选
        ############################################################################################

        # select count(id), num from t11 group by num having max(id) > 5;
        # 反正分组最后只会显示一组,
        # 聚合后,在having 看同一组中的id哪个大,然后和5判断,如果大于5,执行count(id), num
        # 不大于,这一组就不会执行后面的语句。

    # ================================================================================

order by子句

# order by 子句
    # ======================================================================================================
        SQL ORDER BY 关键字用于对结果集按照一个列或者多个列进行排序
            SELECT column_name(s) FROM table_name ORDER BY column_name [ASC|DESC] [, column_name [ASC|DESC]];

            SQL 排序有几个重点:

            1. ORDER BY 关键字默认按照升序对记录进行排序
               如需要按照降序对记录进行排序,可以使用 DESC 关键字

            2. 如果没有 ORDER BY 语句,结果集会以 主键 升序排序
               一般情况下,主键都是 id

        # 排序:
        # order by id desc; 降序
        # order by id asc; 升序

        多列排序,那么每个排序字段使用逗号 ( , ) 分隔
            # order by id desc, age asc;  # 根据id降序排列,如果有相同的,按照age升序排列
            按照排序字段从左往右 ( id, age )
                如果第一个排序字段 ( id ) 的值不一样,则按照第一个排序字段的值排序
                如果第一个排序字段 ( id ) 的值一样,则按照第二个排序字段 ( age ) 的值排序
                以此类推

        # order by 可以使用别名进行排序
        # 通常ORDER BY使用的列将是为显示而显示的列,但不一定总是这样,可以用非检索的列排序。
        # 对某一列排序,影响的是整张表
    # =======================================================================================================

limit子句

# limit 子句:
    # ========================================================================================================
        用于限制返回结果集的条数

        # select * from t11 limit 5;  # 取前5行, # 默认初始位置为0
        # select * from t11 limit 5,5;  # 从索引为5的行开始, 然后包含这一条在内往后查5条
        # select * from t11 limit 5 offset 4;  等价 limit 5,4;

        因为LIMIT的机制是每次都是从头开始扫描,如果需要从第60万行开始,读取3条数据
        就需要先扫描定位到60万行,然后再进行读取,而扫描的过程是一个非常低效的过程。
        所以,对于大数据处理时,是非常有必要在应用层建立一定的缓存机制
        (现在的大数据处理,大都使用缓存)

    # ========================================================================================================

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!