MySQL数据库的函数与分组_第四篇(一万字非常详细)

前言

一、创建计算字段

1. 计算字段

  • 存储在数据库表中的数据一般不是应用程序所需要的格式。 例如,如果想在一个字段中既显示公司名,又显示公司的地址,但这两个信息一般包含在不同的表列中。我们需要直接从数据库表中检索出转换、计算或格式化过后的数据。
  • 这就是计算字段发挥作用的所在了。与前面介绍过的列不同,计算字段并不实际存在于数据库表中。计算字段是运行时在SELECT语句内直接创建的。
  • 字段(field) :基本上与列(column)的意思相同,经常互换使用,不过数据库表中的列一般称为列,而术语字段通常用在计算字段的连接上。

2. 拼接字段

  • 为了说明如何使用计算字段,举一个创建由两列组成的标题的简单例子。

vendors表包含供应商名和位置信息。假如要生成一个供应商报表,需要在供应商的名字中按照name(location)这样的格式列出供应商的位置。

  • 此报表需要单个值,而表中数据存储在两个列vend_name和vend_ country中。此外,还需要用括号将vend_country括起来,而这些东西都没有明确存储在数据库表中。
  • 解决办法是把这两个列拼接起来。在MySQL的SELECT语句中,可使用Concat()函数来拼接两个列。如下:
  • 输入 :
    SELECT Concat(vend_name,‘(’,vend_country,‘)’)
    FROM vendors
    ORDER BY vend_name;
  • 输出:
    在这里插入图片描述
  • 分析:Concat()函数用来拼接串,即把多个串连接起来形成一个较长的串。Concat() 需要一个或多个指定的串,各个串之间用逗号分隔。上面的SELECT语句连接以下4个元素:
    • 存储在vend_name列中的名字;
    • 包含一个空格和一个左圆括号的串;
    • 存储在vend_country列中的国家;
    • 包含一个右圆括号的串。
  • 从上述输出中可以看到,SELECT语句返回包含上述4个元素的单个列(计算字段)。

3. 使用别名

  • 从前面的输出中可以看到,SELECT语句拼接地址字段工作得很好。但这个新计算列的名字是什么呢?实际上它没有名字,它只是一个值。
  • 如果仅在SQL查询工具中查看一下结果,这样可以。但是,一个未命名的列不能很好地应用于客户机中,因为客户机没有办法引用它。
  • 为了解决这个问题,SQL支持列别名。别名(alias)是一个字段或值
    的替换名。别名用AS关键字赋予。请看下面的SELECT语句:
  • 输入 :
    SELECT Concat(vend_name,‘(’,vend_country,‘)’) AS vend_title
    FROM vendors
    ORDER BY vend_name;
  • 输出:
    在这里插入图片描述
  • 分析:SELECT语句本身与以前使用的相同,只不过这里的语句中计算字段之后跟了文本AS vend_title。它指示SQL创建一个包含指定计算字段的列名为vend_title的列。从输出中可以看到,结果与以前的相同,但现在列名为vend_title,任何客户机应用都可以按名字引用这个列,就像它是一个实际的表列一样。

4. 执行算术计算

  • 计算字段的另一常见用途是对检索出的数据进行算术计算。举一个例子,orders表包含收到的所有订单,orderitems表包含每个订单中的各项物品。下面的SQL语句检索订单号20005中的所有物品:
  • 输入 :
    SELECT prod_id, quantity, item_price
    FROM orderitems
    WHERE order_num = 20005;
  • 输出:
    在这里插入图片描述
  • item_price列包含订单中每项物品的单价。如下汇总物品的价格(单价乘以订购数量):
  • 输入 :
    SELECT prod_id, quantity, item_price, quantity*item_price AS expanded_price
    FROM orderitems
    WHERE order_num = 20005;
  • 输出:
    在这里插入图片描述
  • 分析:输出中显示的expanded_price列是一个计算字段,此计算字段的算数计算表达式为quantity*item_price。客户机应用现在可以使用这个新计算的列,就像使用其他列一样。
  • MySQL支持下表中列出的基本算术操作符。此外,圆括号可用来区分优先顺序。
    在这里插入图片描述
  • 补充:如何简单试验计算和函数的结果。
  • SELECT语句提供了测试和试验函数与计算的一个很好的办法。虽然SELECT通常用来从表中检索数据,但可以省略FROM子句以便简单地访问和处理表达式。
  • 例如,SELECT 3*2; 将返回 6。SELECT Trim(’ abc ');将返回ab。而SELECT Now(),则是利用Now()函数 返回当前日期和时间。通过这些例子,可以明白如何根据需要简单地使用SELECT语句进行试验。

二、使用函数处理数据

1. 函数

  • 大多数SQL实现支持以下类型的函数。
     用于处理文本串(如删除或填充值,转换值为大写或小写)的文本函数。
     用于在数值数据上进行算术操作(如返回绝对值,进行代数运算)的数值函数。
     用于处理日期和时间值并从这些值中提取特定成分(例如,返回两个日期之差,检查日期有效性等)的日期和时间函数。
     返回DBMS正使用的特殊信息(如返回用户登录信息,检查版本细节)的系统函数。

1.1 文本处理函数

  • 假如我们想将文本数据全部转成大写字母,可以使用Upper() 函数,举例如下:
  • 输入:
    SELECT vend_name, Upper(vend_name) AS vend_name_upper
    FROM vendors
    ORDER BY vend_name;
  • 输出:
    在这里插入图片描述
  • 分析:正如所见,Upper()函数将文本中的字母都转换为大写,本例中每个供应商有两列,第一列为原始的vendors表中存储的值,第二列作为列vend_name_upper将供应商的名字都转换为大写。
  • 下表列出一些常用的文本处理函数:
    在这里插入图片描述
    在这里插入图片描述
  • 表中的SOUNDEX() 函数需要做进一步的解释。SOUNDEX() 是一个将任何文本串换为描述其语音表示的字母数字模式的算法。SOUNDEX() 考虑了类似的发音字符和音节,使得能对串进行发音比较而不是字母比较。

1.2 日期和时间处理函数

  • 下表列出了某些常用的日期和时间处理函数:
    在这里插入图片描述
  • 首先需要注意的是MySQL使用的日期格式。无论你什么时候指定一个日期,不管插入或更新表值还是用WHERE子句进行过滤,日期必须为格式yyyy-mm-dd。因此,2005年9月1日,给出为2005-09-01。

1.3 数值处理函数

  • 数值处理函数仅处理数值数据,下表列出一些常用的数值处理函数:
    在这里插入图片描述

三、汇总数据

1. 聚集函数

  • 我们经常需要汇总数据而不用把它们实际检索出来,为此MySQL提供了专门的函数。 使用这些函数,MySQL查询可用于检索数据,以便分析和报表生成。这种类型的检索例子有以下几种:
    • 确定表中行数(或者满足某个条件或包含某个特定值的行数)。
    • 获得表中行组的和。
    • 找出表列(或所有行或某些特定的行)的最大值、最小值和平均
      值。
  • 为方便这种类型的检索,MySQL给出了5个聚集函数,这些函数能进行上述罗列的检索。
  • 聚集函数(aggregate function) 运行在行组上,计算和返回单个值的函数。
  • 如下表所示:
    在这里插入图片描述

1.1 AVG() 函数

  • AVG() 函数通过对表中行数计数并计算特定列值之和,求得该列的平均值。AVG()可用来返回所有列的平均值,也可以用来返回特定列或行的平均值。
  • 下面的例子使用AVG()返回products表中所有产品的平均价格:
  • 输入:
    SELECT AVG(prod_price) AS avg_price
    FROM products;
  • 输出:
    在这里插入图片描述
  • 分析:此SELECT语句返回值avg_Price,它包含products表中所有产品的平均价格,avg_price是一个别名。
  • AVG()也可以用来确定特定列或行的平均值。下面的例子返回特定供应商所提供产品的平均价格:
  • 输入:
    SELECT AVG(prod_price) AS avg_price
    FROM products
    WHERE vend_id = 1003;
  • 输出:
    在这里插入图片描述
  • 分析:这条SELECT语句与前一条的不同之处在于它包含了WHERE子句。此WHERE子句仅过滤出vend_id=1003的产品,因此avg_price中返回的值只是该供应商的产品的平均值。
  • 注意!AVG()只能用来确定单个特定数值列的平均值,而且列名必须作为函数参数给出。为了获得多个列的平均值,必须使用多个AVG()函数。AVG()函数忽略列值为NULL的行。

1.2 COUNT() 函数

  • COUNT()函数进行计数。可利用COUNT() 确定表中行的数目或符合特定条件的行的数目。
  • COUNT()函数有两种使用方式:
    • 使用COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值。
    • 使用COUNT(column)对特定列中具有值的行进行计数,忽略NULL值。
  • 下面的例子返回customers表中客户的总数:
  • 输入:
    SELECT COUNT(*) AS num_cust
    FROM customers;
  • 输出:
    在这里插入图片描述
  • 分析:在此例子中,利用COUNT(*)对所有行计数,不管行中各列有什么值。计数值在num_cust中返回。不忽略NULL值!
  • 下面的例子只对具有电子邮件地址的客户计数:
  • 输入:
    SELECT COUNT(cust_email) AS num_cust
    FROM customers;
  • 输出:
    在这里插入图片描述
  • 这条SELECT语句使用COUNT(cust_email)对cust_email列中有值的行进行计数。在此例子中,cust_email的计数为3(表示5个客户中只有3个客户有电子邮件地址)。
  • 注意:如果在COUNT() 中指定列名,则指定列的值为NULL的行被COUNT() 函数忽略,不计数;但如果COUNT() 函数中用的是星号(*),则不忽略。

1.3 MAX() 和MIN() 函数

  • MAX()返回指定列中的最大值,MIN()的功能正好与MAX()功能相反,它返回指定列的最小值。这两个函数要求指定列名,如下所示:
  • 输入:
    SELECT MAX(prod_price) AS max_price
    FROM products;
  • 输出:
    在这里插入图片描述
  • MAX()和MIN() 函数都忽略列值为NULL的行,一般用来找出指定列最大/最小的数值或日期值。

1.4 SUM() 函数

  • SUM() 函数用来返回指定列的值的和(总计)。
  • 下面举一个例子,orderitems表包含订单中实际的物品,每个物品有相应的数量(quantity)。可如下检索所订购物品的总数(所有quantity值之和):
  • 输入:
    SELECT SUM(quantity) AS items_ordered
    FROM orderitems
    WHERE order_num = 20005;
  • 输出:
    在这里插入图片描述
  • 分析:函数SUM(quantity)返回订单中所有物品数量之和,WHERE子句保证只统计20005号物品订单中的物品。
  • SUM()函数内还可以进行算数运算,然后再合计多行。在下面的例子中,合计每项物品的item_price*quantity,得出总的订单金额:
  • 输入:
    SELECT SUM(quantity*item_price) AS total_price
    FROM orderitems
    WHERE order_num = 20005;
  • 输出:
    在这里插入图片描述
  • 分析:函数SUM(item_price*quantity)返回订单中所有物品价钱之和,WHERE子句同样保证只统计20005号物品订单中的物品。
  • 如SUM() 函数所示,只要利用标准的算术操作符,以上所有聚集函数都可用来执行多个列上的计算。
  • 同时,SUM() 函数忽略列值为NULL的行。

2. 聚集不同值

  • 以上5个聚集函数都可以如下使用:
    • 对指定列中所有的行执行计算,指定ALL参数或不给参数(因为ALL是默认行为);
    • 只包含指定列中不同的值,指定DISTINCT参数。
  • 下面的例子使用AVG()函数返回特定供应商提供的产品的平均价格。它与上面的SELECT语句相同,但使用了DISTINCT参数,因此平均值只考虑各个不同的价格:
  • 输入:
    SELECT AVG(DISTINCT prod_price) AS avg_price
    FROM products
    WHERE vend_id = 1003;
  • 输出:
    在这里插入图片描述
  • 分析:可以看到,在使用了DISTINCT后,此例子中的avg_price比较高,因为有多个物品具有相同的较低价格。排除它们后提升了平均价格。
  • 注意! 如果指定列名,则DISTINCT只能用于COUNT() 中的指定列。不能用于COUNT(*),因此不允许使用COUNT(DISTINCT *),否则会产生错误。并且,DISTINCT后必须使用列名,不能用于计算或表达式。

四、分组数据

1. 数据分组

  • 到目前为止我们的所有计算都是在表的所有数据,或匹配特定的WHERE子句的数据上进行的。下面的例子返回供应商1003提供的产品数目:
  • 输入:
    SELECT COUNT(*) AS num_prods
    FROM products
    WHERE vend_id = 1003;
  • 输出:
    在这里插入图片描述
  • 但如果要返回每个供应商提供的产品数目怎么办?这就是分组显身手的时候了。分组允许把数据分为多个逻辑组,以便能对每个组进行聚集计算。

2. 创建分组 GROUP BY

  • 分组是在SELECT语句的GROUP BY子句中建立的。理解分组的最好办法是看一个例子:
  • 输入:
    SELECT vend_id, COUNT(*) AS num_prods
    FROM products
    GROUP BY vend_id;
  • 输出:
    在这里插入图片描述
  • 分析:上面的SELECT语句指定了两个列,vend_id包含产品供应商的ID,num_prods为计算字段(用COUNT(*)函数建立)。GROUP BY子句指示MySQL按vend_id 分组数据。这将对每个vend_id计算 num_prods一次。从输出中可以看到,供应商1001有3个产品,供应商1002有2个产品,供应商1003有7个产品,而供应商1005有2个产品。
  • 因为使用了GROUP BY,就不必使用WHERE子句指定要计算和估值的每个组了。
  • 在具体使用GROUP BY子句前,需要知道一些重要的规定。
    1. GROUP BY子句可以包含任意数目的列。这使得能对分组再进行分组(分组嵌套),为数据分组提供更细致的控制。
    2. 如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别的列取回数据)。
    3. GROUP BY子句中列出的每个列都必须是SELECT语句中的检索列或有效的表达式(但不能是聚集函数)。如果在SELECT语句中使用了表达式,则必须在GROUP BY子句中指定相同的表达式,且不能使用别名。
    4. 除聚集函数外,SELECT语句中的出现的每个列都必须在GROUP BY子句中给出。
    5. 如果分组的列中具有NULL值,则NULL值也将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。
    6. GROUP BY子句必须出现在 WHERE子句之后,ORDER BY子句之前。

3. 过滤分组 HAVING

  • 除了能用GROUP BY分组数据外,MySQL还允许过滤分组,规定包括哪些分组,排除哪些分组。例如,可能想要列出至少有两个订单的所有顾客。为得出这种数据,必须基于完整的分组而不是个别的行进行过滤。
  • 在这个例子中WHERE不能完成任务,因为WHERE过滤指定的是行而不是分组。事实上,WHERE没有分组的概念。那么,不使用WHERE 使用什么呢?MySQL为此目的提供了另外的子句,那就是HAVING 子句。HAVING支持所有WHERE操作符,其后面可以跟聚集函数。
  • 举例如下:
  • 输入:
    SELECT vend_id, COUNT(*) AS num_prods
    FROM products
    GROUP BY vend_id
    HAVING COUNT(*) > 2;
  • 输出:
    在这里插入图片描述
  • 分析:这条SELECT语句的前3行类似于上面的语句。最后一行增加了HAVING子句,它过滤掉了COUNT(*) > 2(两个以上的产品)的那些分组1002和1004。
  • 注意!WHERE子句是在数据分组前进行过滤,HAVING在数据分组后进行过滤。这是一个重要的区别,WHERE 子句排除的行不包括在分组中。这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。

举例:假如想进一步过滤上面的语句,使它返回内产品价格大于12的产品数量。

  • 为达到这一点,可增加一条WHERE子句,过滤出过去产品价格大于5的产品。然后再增加HAVING子句过滤出具有两个以上产品的分组。如下:
  • 输入:
    SELECT vend_id, COUNT(*) AS num_prods
    FROM products
    WHERE prod_price > 5
    GROUP BY vend_id
    HAVING COUNT(*) > 2;
  • 输出:
    在这里插入图片描述
  • 分析:这条语句中,第一行是使用了聚集函数的基本SELECT,它与前面的例子很相像。WHERE子句过滤得到所有prod_price>5 的行。然后按vend_id分组数据,HAVING子句过滤计数2以上的分组。

4. 分组和排序

  • 虽然GROUP BY和ORDER BY经常完成相同的工作,但它们是非常不同的。下表汇总了它们之间的差别:
ORDER BYGROUP BY
排序产生的输出分组行,但输出可能不是分组的顺序
任意列都可以使用(甚至非选择的列也可以使用)只可以使用SELECT选择的列或表达式列,而且必须使用每个SELECT中出现的列和表达式
ORDER BY子句不一定需要如果与聚集函数一起使用列(或表达式),则必须使用GROUP BY 子句
  • 一般在使用GROUP BY子句时,应该也给出ORDER BY子句。这是保证数据正确排序的唯一方法。千万不要仅依赖GROUP BY排序数据。

5. SELECT子句顺序

  • 下面回顾一下SELECT语句中子句的顺序。下表以在SELECT语句中使用时必须遵循的次序,列出迄今为止所学过的子句。
    在这里插入图片描述
    在这里插入图片描述
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林二月er

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值