ORDER BY 子句—对查询结果进行排序

 ORDER BY 子句——对查询结果进行排序 
     我们一般需要让输出以某种方式进行排序,这其实是一个很重要的问题。事实上,我们经常需要能够将找出的数据做一个系统的显示。这可能是升序(aSCending) 或是降序(descending) 。这时,我们就可以运用 ORDER BY 这个指令,以用户指定的列表格式对查询结果进行排序。
一、ORDER BY 子句的格式
     语法:SELECT 列名 FROM 表名
          [ WHERE 条件 ]
          ORDER BY 列名 [ ASC | DESC ]; 
     叙述:[ ] 代表WHERE 子句不是一定需要的。不过,如果WHERE 子句存在的话,它是在 ORDER BY 子句之前。
    ASC 代表结果会以升序(字符 A 到 Z,数字0到9 )列出,而 DESC 代表结果会以降序(字符 Z 到 A,数字9到0)列出。如果没有写明的话,默认为 ASC 。如果需要依照多个字段来排顺序,ORDER BY 子句的语法如下:
    ORDER BY 字段1 [ ASC | DESC ], 字段2 [ ASC | DESC ],  . . . 
    例1:我们要依照 Sales 由大往小列出 Store_Information 表里的记录:
         SELECT store_name, Sales, Date FROM Store_Information ORDER BY Sales DESC;
         结果:store_name  Sales  Date
 ----------------------------------------------------------
 Los Angeles  1500  1999-01-05
 Boston   700  1999-01-08
 San FranciSCo  300  1999-01-08
 San Diego  250  1999-01-07
    在以上的例子中,我们用字段名来指定排列顺序的依据。除了字段名外,我们也可以用字段的顺序(依据字段在 SELECT 之后列表里的顺序)。在 SELECT 后的第一个字段为1,第二个字段为2,以此类推。在上面这个例子中,我们用以下这句SQL 可以达到完全一样的效果:
    SELECT store_name, Sales, Date FROM Store_Information ORDER BY 2 DESC;
二、删除大量数据方法
    第4章我们介绍了用 DELETE 语句从表里删除数据的方法,但是如果需要删除的数据量很大,该怎么办呢?这里我们介绍用 ORDER BY 子句和 LIMIT 子句结合删除大量数据的方法。
    假设有一个表 syslogs 有1000万条记录,需要在业务不停止的情况下删除其中 statusid=1 的所有记录,差不多有600万条。直接执行语句:DELETE FROM syslogs WHERE statusid=1;
    会发现删除失败,显示 lock wait timeout exceed 的错误,因为这条语句所涉及的记录数太多。
    因此我们通过 LIMIT 参数分批删除,比如每10000条进行一次删除,那么我们可以利用这样的语句来完成:
    DELETE FROM syslogs
    WHERE statusid=1
    ORDER BY statusid
    LIMIT 10000;
    然后分多次执行就可以把这些记录成功删除。
三、聚合函数
    既然数据库中有许多记录都是以数字的型态存在,一个很重要的用途就是要能够对这些数字做一些运算,例如将它们总合起来,或是找出它们的平均值。SQL提供的统计函数称为聚合函数.
    主要的聚合函数包括:记数函数: COUNT(列名)  计算元素的个数
                        求和函数: SUM(列名) 对某一列的值求和,但属性必须是整型
                        计算平均值:AVG(列名) 对某一列的值计算平均值
                        求最大值: MAX(列名)  找出某一列的最大值
                        求最小值: MIN(列名)  找出某一列的最小值
        运用函数的语法是:SELECT  函数名(列名) FROM  表名;
        例2:若我们要由 Store_Information 表里:tore_name  Sales  Date
 ----------------------------------------------------------
 Los Angeles  1500  1999-01-05
 San Diego  250  1999-01-07
 Los Angeles  300  1999-01-08
 Boston   700  1999-01-08
 求出营业额的总合(营业总额),可以用以下语句:
 SELECT SUM(Sales) AS Total_Sales FROM Store_Information;
        结果: Total_Sales
 -------------
 2750
        其中 2750 代表所有 Sales 的总合: 1500 + 250 + 300 + 700.
        例3:找出 Store_Information 表里有几条 store_name 列不是空白的记录时,可以用:
 SELECT COUNT(store_name)
 FROM Store_Information
 WHERE store_name is NOT NULL;
        结果: Count(store_name)
 ---------------------------
 4

 COUNT 和 DISTINCT 经常被合起来使用,目的是找出表里有多少条不同的记录(至于这些记录实际上是什么并不重要)。
   例4:如果我们要找出我们的表格中有多少个不同的 store_name,可以用: SELECT COUNT(DISTINCT store_name) FROM Store_Information; 
       结果:Count(DISTINCT store_name)
 ----------------------------------------
 3
四、别名设置
    接下来,我们讨论 alias(别名)在 SQL 上的用处。最常用到的别名有两种:字段别名和表别名。
    简单地来说,使用字段别名的目的是为了让 SQL 产生的结果易读。在前面的例子中,当我们计算营业额总合时,用到了 SUM(Sales) 。如果这个查询项不是一个简单的总合,而是一个复杂的计算,那么输出结果就没有这么易懂了。所以我们用了字段别名,可以确认结果中的名称是简单易懂的。要给字段取个别名,只要在 SELECT 语句的查询项后空一格,然后再写出要用的别名就可以了。
    第二种别名是表别名。要给一个数据表取一个别名,只要在 FROM 子句中的表名后空一格,然后再列出要用的表别名就可以了。这在我们要用 SQL 语句从不同的表里获取数据时是很方便的。这一点我们在后面讲到表连接(join)时会看到。
    1、用空格设置别名
        语法:SELECT  查询项 别名 FROM 表名 表别名;
        这两种别名都是放在它们要替代的项目后面,中间由一个空格分开。
        我们继续使用 Store_Information 表来做例子。
        例5:Store_Information 表的内容如下所示:
        store_name  Sales  Date
 ----------------------------------------------------------
 Los Angeles  1500  1999-01-05
 San Diego  250  1999-01-07
 Los Angeles  300  1999-01-08
 Boston   700  1999-01-08
     算出每一间店(store_name)的营业额(Sales)总合:SELECT A1.store_name Store, SUM(A1.Sales) "Total Sales" FROM Store_Information A1 GROUP BY A1.store_name; 
     结果:Store   Total Sales
 ------------------------------------------
 Los Angeles  1800
 San Diego  250
 Boston   700 
    在结果中,数据本身没有不同。不同的是字段的标题。这是运用字段别名的结果。在第二个字段上,原本我们的标题是"Sum(Sales)" ,而现在我们有一个很清楚的"Total Sales" ,能够比"Sum(Sales)" 更精确地阐述这个字段的含意。
    利用字段别名可以自定义字段的标题,还可以让我们用比较简洁的名称来引用某个字段。注意:当字段名称在 SELECT 语句里别重新命名时,其名称实际上并没有被修改,这种改变只在特定的 SELECT 语句里有效。
   2、用 AS 设置别名
   (1)AS 字段别名
       语法:SELECT 字段 AS 字段别名 FROM 表名
   (2)AS 表别名
      语法:SELECT 字段 FROM  表名 AS 表别名
      例6:给表设置别名:SELECT   s.sno, s.sname FROM student as s;
      例7:查询重复出现次数最多的记录:SELECT keyword, count( * ) AS count FROM article_keyword GROUP BY keyword ORDER BY count DESC LIMIT 20;
     此段查询语句返回 article_keyword 表中 keyword 重复次数(count)最多的20条记录。
     SELECT DISTINCT count( * ) AS count FROM article_keyword GROUP BY keyword ORDER BY count DESCLIMIT 6;
    此段查询语句返回 article_keyword 表中 keyword 的重复次数(count)排名前 6 的数值。通过添加 DISTINCT 返回唯一记录。
五、查询举例
    有学生信息表 student (id, name, chinese, english, math),包括学号、姓名、语文成绩、英语成绩、数学成绩五个字段。
    完成如下查询:
    1、查询表中所有学生的信息
    select id,name,chinese,english,math from student;
    select * from student;
    2、查询表中所有学生的姓名和对应的英语成绩
    select name,english from student;
    3、过滤表中重复数据
    select distinct english from student;
    4、在所有学生的英语分数上加10分特长分
    select name,english+10 from student;
    5、统计每个学生的总分
   select name,(english+chinese+math) from student;
    6、使用别名表示学生分数
    select name as 姓名,(english+chinese+math) as 总分 from student;
    select name 姓名,(english+chinese+math) 总分 from student;
    7、查询姓名为“王五”的学生成绩
    select * from student where name='王五';
    8、查询英语成绩大于90分的同学
    select * from student where english>90;
    9、查询总分大于200分的所有同学
    select * from student where (english+chinese+math)>200;
    10、查询英语分数在 80-90之间的同学
   select * from student where english>80 and english<90;
   select * from student where english between 80 and 90;
    11、查询数学分数为89,90,91的同学
   select * from student where math=80 or math=90 or math=91;
   select * from student where math in(80,90,91);
    12、查询所有姓李的学生成绩
   select * from student where name like '李%';
    13、对数学成绩排序后输出
   select name,math from student order by math;
    14、对总分排序后输出,然后再按从高到低的顺序输出
  select name from student order by (math+english+chinese) desc;
    15、对姓“李”的学生成绩排序输出
  select name 姓名,(math+english+chinese) 总分 from student where name like '李%' order by (math+english+chinese) desc;
    16、统计一个班级共有多少学生
  select count(*) from student;
  select count(name) from student;
    17、统计数学成绩大于90的学生有多少个
  select count(*) from student where math>90;
    18、统计总分大于250的人数有多少
  select count(*) from student where (math+english+chinese)>250;
    19、统计一个班级数学总成绩
  select sum(math) from student;
    20、统计一个班级语文、英语、数学各科的总成绩
  select sum(math),sum(chinese),sum(english) from student;
    21、统计一个班级语文、英语、数学的成绩总和
  select sum(chinese+math+english) from student;
    22、统计一个班级语文成绩平均分
  select sum(chinese)/count(chinese) from student;
    23、求一个班级数学平均分
  select avg(math) from student;
    24、求一个班级总分平均分
  select avg(chinese+english+math) from student;
    25、求班级最高分和最低分
  select max(chinese+english+math), min(chinese+english+math) from student;

【参考资料】
   W3SChool 在线SQL教程   http://www.w3SChool.com.cn/sql/sql_orderby.asp  SQL ORDER BY 子句
   http://www.w3SChool.com.cn/sql/sql_func.asp  SQL 函数
   http://www.w3SChool.com.cn/sql/sql_func_avg.asp  SQL AVG 函数
   http://www.w3SChool.com.cn/sql/sql_func_count.asp  SQL COUNT() 函数
   http://www.w3SChool.com.cn/sql/sql_func_max.asp  SQL MAX() 函数
   http://www.w3SChool.com.cn/sql/sql_func_min.asp  SQL MIN() 函数
   http://www.w3SChool.com.cn/sql/sql_func_sum.asp  SQL SUM() 函数
   http://www.w3SChool.com.cn/sql/sql_alias.asp  SQL Alias(别名)

课后练习:
       1. 回答以下问题:
        1)说出任何SELECT语句都需要的组成部分。
        2)在WHERE子句里,任何数据都需要使用单引号吗?
        3)SELECT语句属于SQL语言里的哪一类命令?
        4)WHERE字句里能使用多个条件吗?
        5)DISTINCT选项的作用是什么?
        6)选项ALL是必须的吗
        7)在基于字符字段进行排序时,数字字符是如何处理的?
      2. 输入以下SELECT命令,判断其语法是否正确,如果不正确就进行必要的修改。这里使用的是表EMPLOYEE_TBL。
 a.
 SELECT  EMP_ID , LAST_NAME, FIRST_NAME,
 FROM  EMPLOYEE_TBL;
 b.
 SELECT  EMP_ID , LAST_NAME
 ORDER BY  EMPLOYEE_TBL
 FROM  EMPLOYEE_TBL;
 c.
 SELECT  EMP_ID , LAST_NAME, FIRST_NAME
 FROM  EMPLOYEE_TBL
 WHERE  EMP_ID='213764555'
 ORDER BY  EMP_ID;
 d.
 SELECT EMP_ID SSN, LAST_NAME
 FROM EMPLOYEE_TBL
 WHERE EMP_ID='213764555'
 ORDER BY 1;
 e.
 SELECT EMP_ID , LAST_NAME, FIRST_NAME
 FROM EMPLOYEE_TBL
 WHERE EMP_ID='213764555'
 ORDER BY 3,1,2;
 f.
 SELECT LAST_NAME , FIRST_NAME , PHONE
 FROM  EMPLOYEE_TBL
 WHERE  EMP_ID='333333333';
        3.使用下面这个表 CUSTOMER_TBL,编写一条 SELECT 语句,选择住在 Indiana、Ohio、Michiga 和 Illinois 并且姓名以字母A或B开头的客户,返回它们的ID和姓名(以字母顺序)。
   DESCRIBE  CUSOMER_TBL;
   NAME                NULL?     Type
 CUST_ID                  NOT NULL       VARCHAR(10)
 CUST_NAME         NOT NULL       VARCHAR(30)
 CUST_ADDRESS NOT NULL       VARCHAR(20)
 CUST_CITY NOT NULL        VARCHAR(12)
 CUST_STATE NOT NULL        VARCHAR(2)
 CUST_ZIP   NOT NULL        VARCHAR(5)
 CUST_PHONE                               VARCHAR(10)
 CUST_FAX                                  VARCHAR(10)
        4. 编写一个 SELECT 语句,从表 PRODUCTS_TBL 返回以下信息:产品描述、产品价格、每个产品5%的销售税。产品列表按价格从高到低排列。
        5. 编写一个SELECT语句,从表 PRODUCTS_TBL 返回以下信息:产品描述、产品价格、每个产品5%的销售税,加上销售税的总价。产品列表按价格从高到低排列。有两种方法可以实现。
        6. 有学生表 Student(Sno, Sname, Sage, Sdept),包括字段学号、姓名、年龄、系名;
         及成绩表 SC(studentid, courseid,grade),包括字段学生学号、课程编号、成绩。
         完成以下查询:
         1)查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列。
         2)查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。
         3)查询全体学生的姓名、年龄,要求按照年龄降序排序。
         4)查询学生总数。
         5)查询选修了课程的学生人数。
         6)查询1号课程的学生平均成绩。
         7)查询1号课程的学生最高分和最低分。