Tas02 基础查询与排序

本文详细介绍了SQL中的基础查询与排序操作,包括SELECT、WHERE、运算符、聚合函数、分组、HAVING子句和ORDER BY子句的使用。通过实例展示了如何筛选数据、计算统计值、分组过滤以及对结果进行排序。此外,还探讨了NULL值的处理和GROUP BY与ORDER BY子句的执行顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二、基础查询与排序
2.1语句基础
  • SELECT语句:

    SELECT <列名>, ... FROM <表名>
  • WHERE语句:

    • SELECT通过WHERE来指定查询条件
    SELECT <列名>... FROM <表名>  WHERE <条件表达式>;
    
  • 相关法则:

    • “*”:代表全部列

    • SQL中可以随意使用换行符,不影响语句执行(但不可插入空行)

    • 设定汉语别名时需要使用双引号括起来

    • 在SELECT语句中使用DISTINCT可以删除重复行

    • 注释:

      - 一行注释,“--”
      - 多行注释,“/* */”
      
      -- 使用AS关键字为列表设别名
      SELECT product_id AS id,
      	   product_name AS name,
      	   purchase_price AS "进货单价"
      	FROM product;
      -- 使用DISTINCT删除product_type列中的重复行
      SELECT DISTINCT product_type
      	FROM product;
      
2.2运算符
  • 算术运算符: + - * /

  • 比较运算符:

    • “=”: 和…相等

    • “<>”: 和… 不相等

    • “>=”、“>”、“<=”、“<”

  • 常用法则:

    • SELECT子句中可以使用常数或者表达式
    • 使用比较运算符时一定要注意不等号和等号的位置
    • 字符串类型的数据原则上按照字典顺序进行排序,不能与数字的大小顺序混淆。
    • 希望选取NULL记录时,需要在条件表达式中使用IS NULL运算符。希望选取不是NULL的记录时,需要在条件表达式中使用IS NOT NULL运算符
    -- SQL语句使用运算表达式
    SELECT product_name, sale_price, sale_price * 2 AS "sale price x2"
    	FROM product;
    -- WHERE 子句的条件表达都也可以使用计算表达式
    SELECT product_name, sale_price, purchase_price
    	FROM product
    	WHERE sale_price - purchase_price >= 500;
    /* 对字符串使用不等号,首先创建chars并插入数据
    选出大于‘2’的SELECT语句*/
    -- 创建表
    CREATE TABLE chars
    (chr CHAR(3) NOT NULL,
    PRIMARY KEY(chr));
    -- 选出大于‘2’的数据SELECT语句
    SELECT chr
    	FROM chars
    	WHERE chr > '2';
    -- 选取NULL的记录
    SELECT product_name, purchase_price
    	FROM product
    	WHERE purchase_name IS NULL;
    -- 选取不为NULL的记录
    SELECT purchase_price, purchase_price
    	FROM product
    	WHERE purchase_price IS NOT NULL
    
  • NOT运算符:

    • 除了"<>",NOT也表示否定

    • NOT不能单独使用,必须和其他查询条件组合起来使用:

      SELECT product_name, product_type, sale_price
      	FROM product
      	WHERE sale_price >= 1000;
      
      SELECT product_name, product_type, sale_price
      	FROM product
      	WHERE NOT sale_price >= 1000;   -- 等价于 <
      
    • AND 和 OR运算符:

      /*“商品种类为办公用品”并且“登记日期是 2009 年 9 月 11 日或者 2009 年 9 月 20 日”理想结果为“打孔器”*/
      -- 但当你输入以下信息时,会得到错误结果
      SELECT product_name, product_type, regist_date
      	FROM product
      	WHERE product_type = '办公用品'
      	AND regist_date = '2009-09-11'
          OR regist_date = '2009-09-20';
      
      • 错误的原因: AND 运算符优先于 OR 运算符 ,想要优先执行OR运算,可以使用 括号

        -- 正确结果
        -- 通过使用括号让OR运算符先于AND运算符执行
        SELECT product_name, product_type, regist_date
        	FROM product
        	WHERE product_type = '办公用品'
            AND ( regist_date = '2009-09-11'
                OR regist_date = '2009-09-20');
        
  • 真值表:

    • NULL的真值结果既不为真,也不为假,因为并不知道这样一个值
    • 这时真值是除真假之外的第三种值——不确定(UNKNOWN
    • 只有 SQL 中的逻辑运算被称为三值逻辑,其他语言只有真 假(二值逻辑)
2.4 聚合函数
  • 五个常用的聚合函数:

    • COUNT:计算表中的记录数(行数)
    • SUM: 计算表中数值列中数据的合计值
    • AVG: 计算表中数值列中数据的平均值
    • MAX: 求出表中任意列中数据的最大值
    • MIN: 求出表中任意列中数据的最小值
    -- 计算全部数据的行数(包含NULL)
    SELECT COUNT(*)
      FROM product;
    -- 计算NULL以外数据的行数
    SELECT COUNT(purchase_price)
      FROM product;
    -- 计算销售单价和进货单价的合计值
    SELECT SUM(sale_price), SUM(purchase_price) 
      FROM product;
    -- 计算销售单价和进货单价的平均值
    SELECT AVG(sale_price), AVG(purchase_price)
      FROM product;
    -- MAX和MIN也可用于非数值型数据
    SELECT MAX(regist_date), MIN(regist_date)
      FROM product;
      
    -- 计算去除重复数据后的数据行数
    SELECT COUNT(DISTINCT product_type)
     FROM product;
    -- 是否使用DISTINCT时的动作差异(SUM函数)
    SELECT SUM(sale_price), SUM(DISTINCT sale_price)
     FROM product;
    
  • 常用法则:

    • COUNT函数的结果根据参数的不同而不同。COUNT(*)会得到包含NULL的数据行数,而COUNT(<列名>)会得到NULL之外的数据行数。
    • 聚合函数会将NULL排除在外。但COUNT(*)例外,并不会排除NULL。
    • MAX/MIN函数几乎适用于所有数据类型的列。SUM/AVG函数只适用于数值类型的列。
    • 想要计算值的种类时,可以在COUNT函数的参数中使用DISTINCT。
    • 在聚合函数的参数中使用DISTINCT,可以删除重复数据。
2.5 对表进行分组
  • GROUP BY语句

    -- 分组汇总
    SELECT <列名1>,<列名2>, <列名3>, ……
      FROM <表名>
     GROUP BY <列名1>, <列名2>, <列名3>, ……;
     
     -- 按照商品种类统计数据行数
    SELECT product_type, COUNT(*)
      FROM product
     GROUP BY product_type;
     -- 不含GROUP BY,会报错
    SELECT product_type, COUNT(*)
      FROM product
    
    • 在 GROUP BY 子句中指定的列称为聚合键或者分组列
    • 聚合键包含NULL时,会将NULL作为一组特殊数据处理
  • GROUP BY书写顺序子句顺序有严格要求:

    • SELECT → 2. FROM → 3. WHERE → 4. GROUP BY

    • 其中前三项用于筛选数据,GROUP BY对筛选出的数据进行处理

      SELECT purchase_price, COUNT(*)
        FROM product
       WHERE product_type = '衣服'
       GROUP BY purchase_price;
      
  • 常见错误:

    • 在聚合函数的SELECT子句中写了聚合键以外的列使用COUNT等聚合函数时,SELECT子句中如果出现列名,只能是GROUP BY子句中指定的列名(也就是聚合键)。
    • 在GROUP BY子句中使用列的别名SELECT子句中可以通过AS来指定别名,但在GROUP BY中不能使用别名。因为在DBMS中 ,SELECT子句在GROUP BY子句后执行。
    • 在WHERE中使用聚合函数原因是聚合函数的使用前提是结果集已经确定,而WHERE还处于确定结果集的过程中,所以相互矛盾会引发错误。 如果想指定条件,可以在SELECT,HAVING(下面马上会讲)以及ORDER BY子句中使用聚合函数。
2.6 为聚合结果指定条件
  • 用HAVING子句得到特定(例如只取两组)分组

    • WHERE不可行,因为,WHERE子句只能指定记录(行)的条件,而不能用来指定组的条件(例如,“数据行数为 2 行”或者“平均值为 500”等)。
    • HAVING的用法类似WHERE
  • HAVING特点:

    • HAVING子句用于对分组进行过滤,可以使用数字、聚合函数和GROUP BY中指定的列名(聚合键)。

      -- 数字
      SELECT product_type, COUNT(*)
        FROM product
       GROUP BY product_type
      HAVING COUNT(*) = 2;
      -- 错误形式(因为product_name不包含在GROUP BY聚合键中)
      SELECT product_type, COUNT(*)
        FROM product
       GROUP BY product_type
      HAVING product_name = '圆珠笔';
      
2.7为查询结果进行排序
  • ORDER BY子句:

    SELECT <列名1><列名2><列名3>...
    FROM <表名>
    ORDER BY <排序基准列1>, <排序基准列2>,...
    
    -- 默认为升序,降序排列为DESC
    -- 降序排列
    SELECT product_id, product_name, sale_price, purchase_price
      FROM product
     ORDER BY sale_price DESC;
    -- 多个排序键
    SELECT product_id, product_name, sale_price, purchase_price
      FROM product
     ORDER BY sale_price, product_id;
    -- 当用于排序的列名中含有NULL时,NULL会在开头或末尾进行汇总。
    SELECT product_id, product_name, sale_price, purchase_price
      FROM product
     ORDER BY purchase_price;
    
  • ORDER BY中列名,可以使用别名

  • GROUP BY 子句中不能使用SELECT 子句中定义的别名,但是在 ORDER BY 子句中却可以使用别名。为什么在GROUP BY中不可以而在ORDER BY中可以呢?

  • 因为SQL在使用 HAVING 子句时 SELECT 语句的顺序为:

    FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。
    
  • 其中SELECT的执行顺序在 GROUP BY 子句之后,ORDER BY 子句之前。也就是说,当在ORDER BY中使用别名时,已经知道了SELECT设置的别名存在,但是在GROUP BY中使用别名时还不知道别名的存在,所以不能在ORDER BY中可以使用别名,但是在GROUP BY中不能使用别名

  • 在MySQL中,NULL 值被认为比任何 非NULL 值低,因此,当顺序为 ASC(升序)时,NULL 值出现在第一位,而当顺序为 DESC(降序)时,则排序在最后。

  • 如果想指定存在 NULL 的行出现在首行或者末行,需要特殊处理。

    CREATE TABLE user (
        id INT NOT NULL AUTO_INCREMENT,
        name VARCHAR(5),
        date_login DATE,
        PRIMARY KEY (id)
    );
    
    INSERT INTO user(name, date_login) VALUES
    (NULL,    '2017-03-12'), 
    ('john',   NULL), 
    ('david', '2016-12-24'), 
    ('zayne', '2017-03-02');
    
  • !ISNULL( ) 函数等同于使用 IS NOT NULL 比较运算符。

  • NULL值处理一般有以下两种需求:

    • NULL 值排在末行,同时将所有 非NULL 值按升序排列。
    • NULL 值排在首行,同时将所有 非NULL 值按倒序排列。
2.8 练习题(用到的数据在Task01中可见)
  • 2.8.1 编写一条SQL语句,从 product(商品) 表中选取出“登记日期(regist_date)在2009年4月28日之后”的商品,查询结果要包含 product nameregist_date 两列。

    SELECT product_name, regist_date
    FROM product
    WHERE regist_date > '2009-04-28';
    
  • 2.8.2 请说出对product 表执行如下3条SELECT语句时的返回结果。

    -- 1.
    SELECT *
      FROM product
     WHERE purchase_price = NULL;
     
    -- 2. 
    SELECT *
      FROM product
     WHERE purchase_price <> NULL;
     
    -- 3 
    SELECT *
      FROM product
     WHERE product_name > NULL;
     
     -- 以上均没有输出,显示Empty set。只能使用ISNULL()函数,或者IS NOT NULL比较运算符
    
  • 2.8.3 章节中的SELECT语句能够从 product 表中取出“销售单价(sale_price)比进货单价(purchase_price)高出500日元以上”的商品。请写出两条可以得到相同结果的SELECT语句。执行结果如下所示:

product_name | sale_price | purchase_price 
-------------+------------+------------
T恤衫        |   1000    | 500
运动T恤      |    4000    | 2800
高压锅       |    6800    | 5000
-- (1)
SELECT product_name, sale_price, purchase_price
FROM product
WHERE (sale_price - purchase_price) >= 500;

-- (2)
SELECT product_name, sale_price, purchase_price
FROM product
WHERE (sale_price - purchase_price) <= 500;
  • 2.8.4 请写出一条SELECT语句,从 product 表中选取出满足“销售单价打九折之后利润高于 100 日元的办公用品和厨房用具”条件的记录。查询结果要包括 product_name列、product_type 列以及销售单价打九折之后的利润(别名设定为 profit)。

    • 提示:销售单价打九折,可以通过 sale_price 列的值乘以0.9获得,利润可以通过该值减去 purchase_price 列的值获得。
    SELECT product_name, product_type, (sale_price*0.9 - purchase_price) as profit
    FROM product
    WHERE (sale_price*0.9 - purchase_price) >= 100;
    
    -- 错误写法
    SELECT product_name, product_type, (sale_price*0.9 - purchase_price) as profit
    FROM product
    WHERE profit >= 100;
    -- 错误原因:select子句后的别名,在where条件中不能使用
    -- 牢记以下执行顺序
    FROMWHEREGROUP BYHAVINGSELECTORDER BY
    
  • 2.8.5 请指出下述SELECT语句中所有的语法错误。

    价( purchase_price 列)合计值1.5倍的商品种类。

    SELECT product_id, SUM(product_name)
    --本SELECT语句中存在错误。
      FROM product 
     GROUP BY product_type 
     WHERE regist_date > '2009-09-01';
       
    -- 书写顺序
    SELECT2. FROM3. WHERE4. GROUP BY
    
  • 2.8.6 请编写一条SELECT语句,求出销售单价( sale_price 列)合计值大于进货单价( purchase_price 列)合计值1.5倍的商品种类。执行结果如下所示。

    product_type | sum  | sum 
    -------------+------+------
    衣服         | 5000 | 3300
    办公用品      |  600 | 320
    
    -- 错误写法
    SELECT SUM(sale_price) as sum, SUM(purchase_price) as sum
    FROM product
    WHERE sale_price > purchase_price * 1.5
    GROUP BY product_type;
    
    -- 正确写法,为聚合结果指定条件,要是用HAVING子句,而不是WHERE
    -- (1)
    SELECT product_type, SUM(sale_price) as sum, SUM(purchase_price) as sum
    FROM product
    GROUP BY product_type
    HAVING sum(sale_price) > sum(purchase_price) * 1.5;
    
    -- (2) HAVING子句可以使用SELECT中的别名
    SELECT product_type, SUM(sale_price) as sum_sale, SUM(purchase_price) as sum_purchase
    FROM product
    GROUP BY product_type
    HAVING sum_sale > sum_purchase * 1.5;
    
    
    -- 牢记以下执行顺序
    FROMWHEREGROUP BYHAVINGSELECTORDER BY
    
  • 2.8.7 此前我们曾经使用SELECT语句选取出了product(商品)表中的全部记录。当时我们使用了 ORDER BY 子句来指定排列顺序,但现在已经无法记起当时如何指定的了。请根据下列执行结果,思考 ORDER BY 子句的内容。
    在这里插入图片描述

-- 时间降序,purchase_price 或 sale_price升序
SELECT * FROM product
ORDER BY -regist_date, purchase_price;

-- 或者使用DESC,但是会将NULL值放在末尾
SELECT * FROM product
ORDER BY regist_date DESC, purchase_price;

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值