brbr# 去重(过滤重复数据)br- 在 MySQL 中使用 SELECT 语句执行简单的数据查询时,返回的是所有匹配的记录。如果表中的某些字段没有唯一性约束,那么这些字段就可能存在重复值。为了实现查询不重复的数据,MySQL 提供了 DISTINCT 关键字。br- DISTINCT 关键字的主要作用就是对数据表中一个或多个字段重复的数据进行过滤,只返回其中的一条数据给用户。br- 使用 DISTINCT 关键字时需要注意以下几点:br1. DISTINCT 关键字只能在 SELECT 语句中使用。br2. 在对一个或多个字段去重时,DISTINCT 关键字必须在所有字段的最前面。br3. 如果 DISTINCT 关键字后有多个字段,则会对多个字段进行组合去重,也就是说,只有多个字段组合起来完全是一样的情况下才会被去重。br```shellbr# 对history表的value字段去重brselect distinct history.value from zabbix.hosts,zabbix.items,zabbix.history where hosts.name="zbxproxy03" and items.name="Context switches per second" and items.itemid=history.itemid;brbr# 对history表的clock和value字段去重brselect distinct history.clock,history.value from zabbix.hosts,zabbix.items,zabbix.history where hosts.name="zbxproxy03" and items.name="Context switches per second" and items.itemid=history.itemid;brbr# 查询去重之后的记录的条数brselect count(distinct history.clock,history.value) from zabbix.hosts,zabbix.items,zabbix.history where hosts.name="zbxproxy03" and items.name="Context switches per second" and items.itemid=history.itemid;br```br---br# 别名br- 为了查询方便,MySQL 提供了 AS 关键字来为表和字段指定别名br- 当表名很长或者执行一些特殊查询的时候,为了方便操作,可以为表指定一个别名,用这个别名代替表原来的名称。br- 表的别名不能与该数据库的其它表同名。字段的别名不能与该表的其它字段同名。在条件表达式中不能使用字段的别名br- 表别名只在执行查询时使用,并不在返回结果中显示。而字段定义别名之后,会返回给客户端显示,显示的字段为字段的别名。br1. 表别名br```shellbr# 下面为 zabbix 库中的 hosts 表指定别名 hbrselect h.name,h.host from zabbix.hosts as h where status=0;br```br2. 字段别名br```shellbr# 给h.name字段指定别名“主机名”,inter.ip字段指定别名“ip地址”brmysql> select h.name as "主机名",inter.ip as "ip地址" from zabbix.hosts as h,zabbix.interface as inter where h.name="zbxproxy03" and h.hostid=inter.hostid;br+------------+----------------+br| 主机名 | ip地址 |br+------------+----------------+br| zbxproxy03 | 192.168.11.157 |br+------------+----------------+br1 row in set (0.00 sec)br```
# 对history表的value字段去重select distinct history.value from zabbix.hosts,zabbix.items,zabbix.history where hosts.name="zbxproxy03" and items.name="Context switches per second" and items.itemid=history.itemid;# 对history表的clock和value字段去重select distinct history.clock,history.value from zabbix.hosts,zabbix.items,zabbix.history where hosts.name="zbxproxy03" and items.name="Context switches per second" and items.itemid=history.itemid;# 查询去重之后的记录的条数select count(distinct history.clock,history.value) from zabbix.hosts,zabbix.items,zabbix.history where hosts.name="zbxproxy03" and items.name="Context switches per second" and items.itemid=history.itemid;
# 下面为 zabbix 库中的 hosts 表指定别名 hselect h.name,h.host from zabbix.hosts as h where status=0;
# 给h.name字段指定别名“主机名”,inter.ip字段指定别名“ip地址”mysql> select h.name as "主机名",inter.ip as "ip地址" from zabbix.hosts as h,zabbix.interface as inter where h.name="zbxproxy03" and h.hostid=inter.hostid;+------------+----------------+| 主机名 | ip地址 |+------------+----------------+| zbxproxy03 | 192.168.11.157 |+------------+----------------+1 row in set (0.00 sec)
LIMIT 初始位置,记录数
第1页 limit 0,10 # 按分页显示,每页显示10条记录,从0开始,当前是第1页(第2页的计算方式是,10+0=10,所以,要显示第2页,就要从10开始了)第2页 limit 10,10 # 按分页显示,每页显示10条记录,从10开始,当前是第2页(第3页的计算方式是,10+10=20,所以,要显示第3页,就要从20开始了)第3页 limit 20,10 # 按分页显示,每页显示10条记录,从20开始,当前是第3页第4页 limit 30,10 # 按分页显示,每页显示10条记录,从30开始,当前是第4页第5页 limit 40,10 # 按分页显示,每页显示10条记录,从40开始,当前是第5页...依此类推...
select FROM_UNIXTIME(his.clock),his.value from history as his limit 3,5;
LIMIT 记录数
mysql> select hostid,name from zabbix.hosts where status=0 limit 3;+--------+------------+| hostid | name |+--------+------------+| 10084 | zbxser01 || 10331 | {#HV.NAME} || 10332 | {#VM.NAME} |+--------+------------+3 rows in set (0.00 sec)
LIMIT 记录数 OFFSET 初始位置
mysql> select name from zabbix.hosts limit 5 offset 100;+---------------------------------------------------------------+| name |+---------------------------------------------------------------+| Template Module Windows physical disks by Zabbix agent active || Template Module Windows services by Zabbix agent || Template Module Windows services by Zabbix agent active || Template Module Zabbix agent || Template Module Zabbix agent active |+---------------------------------------------------------------+5 rows in set (0.00 sec)
ORDER BY <字段名> [ASC|DESC]
mysql> select FROM_UNIXTIME(his.clock),his.value from history as his order by his.clock desc limit 0,10;+--------------------------+---------------------+| FROM_UNIXTIME(his.clock) | value |+--------------------------+---------------------+| 2022-03-23 11:39:58 | 0.03327262491210712 || 2022-03-23 11:39:57 | 0.2994525692658531 || 2022-03-23 11:39:57 | 6.7543337663136 || 2022-03-23 11:39:56 | 6.937363366354516 || 2022-03-23 11:39:56 | 1.0364532470703125 || 2022-03-23 11:39:56 | 2.312458609154667 || 2022-03-23 11:39:56 | 0.24791898308140758 || 2022-03-23 11:39:55 | 2.2958371233088815 || 2022-03-23 11:39:55 | 0.3120714025473114 || 2022-03-23 11:39:55 | 0 |+--------------------------+---------------------+10 rows in set (0.15 sec)mysql>
mysql> select FROM_UNIXTIME(his.clock),his.value from history as his order by his.clock,his.value desc limit 0,10;+--------------------------+-------------------+| FROM_UNIXTIME(his.clock) | value |+--------------------------+-------------------+| 2022-03-16 21:46:16 | 96.085049 || 2022-03-16 21:46:16 | 3.914951000000002 || 2022-03-16 21:46:16 | 2.126223 || 2022-03-16 21:46:16 | 0.978738 || 2022-03-16 21:46:16 | 0.759366 || 2022-03-16 21:46:16 | 0.18 || 2022-03-16 21:46:16 | 0.09 || 2022-03-16 21:46:16 | 0.07 || 2022-03-16 21:46:16 | 0.050624 || 2022-03-16 21:46:16 | 0 |+--------------------------+-------------------+10 rows in set (0.17 sec)
注意:在对多个字段进行排序时,排序的第一个字段必须有相同的值,才会对第二个字段进行排序。如果第一个字段数据中所有的值都是唯一的,MySQL 将不再对第二个字段进行排序。
select FROM_UNIXTIME(his.clock),his.value from history as his order by his.clock desc,his.value asc limit 0,100;
# 按clock字段从最新到最旧的时间进行排序,并显示前10行记录mysql> select from_unixtime(his.clock), his.value from zabbix.history as his order by his.clock desc limit 10;+--------------------------+---------------------+| from_unixtime(his.clock) | value |+--------------------------+---------------------+| 2022-03-23 15:28:28 | 0.08122102270804427 || 2022-03-23 15:28:28 | 0.31311299809630666 || 2022-03-23 15:28:27 | 100 || 2022-03-23 15:28:27 | 0 || 2022-03-23 15:28:27 | 0.7355883252732085 || 2022-03-23 15:28:26 | 0 || 2022-03-23 15:28:26 | 0 || 2022-03-23 15:28:26 | 15.969782 || 2022-03-23 15:28:25 | 0.007042 || 2022-03-23 15:28:24 | 9.618901 |+--------------------------+---------------------+10 rows in set (0.16 sec)
在 WHERE 关键词后可以有多个查询条件,这样能够使查询结果更加精确。多个查询条件时用逻辑运算符 AND(&&)、OR(||)或 XOR 隔开。
# 在 events 表中查询 eventid 大于 400,并且 objectid 大于等于 16274 的事件信息,SQL 语句和运行结果如下。mysql> select eventid,objectid,name from zabbix.events where eventid>400 and objectid>=16274; +---------+----------+------------------------------------------------------------------+| eventid | objectid | name |+---------+----------+------------------------------------------------------------------+| 429 | 17775 | More than 100 items having missing data for more than 10 minutes |+---------+----------+------------------------------------------------------------------+1 row in set (0.00 sec)# 在 events 表中查询 eventid 大于 400,并且 objectid 大于等于 15000 的事件信息,SQL 语句和运行结果如下。mysql> select eventid,objectid,name from zabbix.events where eventid>400 and objectid>=15000;+---------+----------+------------------------------------------------------------------+| eventid | objectid | name |+---------+----------+------------------------------------------------------------------+| 429 | 17775 | More than 100 items having missing data for more than 10 minutes |+---------+----------+------------------------------------------------------------------+1 row in set (0.00 sec)
OR、AND 和 XOR 可以一起使用,但是在使用时要注意运算符的优先级
在 MySQL 中,LIKE 关键字主要用于搜索匹配字段中的指定内容。其语法格式如下:
[NOT] LIKE '字符串'
其中:
在 where like 的条件查询中,SQL 提供了四种匹配方式。
查询内容包含通配符时,由于通配符的缘故,导致我们查询特殊字符 “%”、“”、“[” 的语句无法正常实现,而把特殊字符用 “[ ]” 括起便可正常查询。
通配符是一种特殊语句,主要用来模糊查询。当不知道真正字符或者懒得输入完整名称时,可以使用通配符来代替一个或多个真正的字符。
%”是 MySQL 中最常用的通配符,它能代表任何长度的字符串,字符串的长度可以为 0。例如,a%b表示以字母 a 开头,以字母 b 结尾的任意长度的字符串。该字符串可以代表 ab、acb、accb、accrb 等字符串。有些情况下若是中文,请使用两个百分号(%%)表示。
案例:从hosts表中的name字段查找所有以“T”开头的记录
mysql> select name from zabbix.hosts where name like 'T%';+-----------------------------------------------------------------------------+| name |+-----------------------------------------------------------------------------+| Template APP Apache Kafka by JMX || Template App Apache Tomcat JMX || Template App Apache by HTTP || Template App Apache by Zabbix agent || Template App Ceph by Zabbix Agent2 |
注意:匹配的字符串必须加单引号或双引号。
案例:从hosts表中的name字段查找所有不以“T”开头的记录
mysql> select name from zabbix.hosts where name not like 'T%';+--------------+| name |+--------------+| mysql-db02 || mysql-master || zbxproxy01 || zbxproxy02 || zbxproxy03 || zbxproxy04 || zbxser01 || zbxser02 |
案例:从hosts表中的name字段查找包含有CPU的记录
mysql> select name from zabbix.hosts where name like '%CPU%';+----------------------------------------------------+| name |+----------------------------------------------------+| Template Module Cisco OLD-CISCO-CPU-MIB SNMP || Template Module HOST-RESOURCES-MIB CPU SNMP || Template Module Linux CPU SNMP || Template Module Linux CPU by Zabbix agent || Template Module Linux CPU by Zabbix agent active || Template Module Windows CPU by Zabbix agent || Template Module Windows CPU by Zabbix agent active |+----------------------------------------------------+7 rows in set (0.00 sec)
“_”只能代表单个字符,字符的长度不能为 0。例如,a_b可以代表 acb、adb、aub 等字符串。 案例:在 hosts 表中,查找所有以数字“01”结尾,且“01”前面只有 6 个字符的名称,SQL 语句和运行结果如下。
mysql> select name,status from zabbix.hosts where status=0 and name like '______01';+----------+--------+| name | status |+----------+--------+| zbxser01 | 0 |+----------+--------+1 row in set (0.00 sec)
默认情况下,LIKE 关键字匹配字符的时候是不区分大小写的。如果需要区分大小写,可以加入 BINARY 关键字。
# 匹配t开头的行记录,并区分大小写mysql> select name,status from zabbix.hosts where name like binary 't%';Empty set, 1 warning (0.00 sec)
注意:mysql8貌似已经废除了该特性,mysql5是可以的
下面是使用通配符的一些注意事项:
下面是一些使用通配符要记住的技巧。
总之,通配符是一种极其重要和有用的搜索工具,以后我们会经常用到它。
MySQL 提供了 BETWEEN AND 关键字,用来判断字段的数值是否在指定范围内。 BETWEEN AND 需要两个参数,即范围的起始值和终止值。如果字段值在指定的范围内,则这些记录被返回。如果不在指定范围内,则不会被返回。 使用 BETWEEN AND 的基本语法格式如下:
[NOT] BETWEEN 取值1 AND 取值2
案例:查询2022年3月23号上午10点到11点这个时间段的历史数据
# 确定起始时间和结束时间的时间戳mysql> select itemid,from_unixtime(clock),clock,value,ns from zabbix.history where from_unixtime(clock) like '2022-03-23 10:00:02%';+--------+----------------------+------------+-------+-----------+| itemid | from_unixtime(clock) | clock | value | ns |+--------+----------------------+------------+-------+-----------+| 29162 | 2022-03-23 10:00:02 | 1648000802 | 0 | 277202868 | # 起始时间+--------+----------------------+------------+-------+-----------+1 row in set (0.70 sec)mysql> mysql> select itemid,from_unixtime(clock),clock,value,ns from zabbix.history where from_unixtime(clock) like '2022-03-23 11:00:01%';+--------+----------------------+------------+-----------+----------+| itemid | from_unixtime(clock) | clock | value | ns |+--------+----------------------+------------+-----------+----------+| 33064 | 2022-03-23 11:00:01 | 1648004401 | 87.926269 | 39923084 | # 结束时间+--------+----------------------+------------+-----------+----------+1 row in set (0.76 sec)mysql> # 通过BETWEEN AND 关键字来做范围查询,语句如下mysql> select itemid,from_unixtime(clock),clock,value,ns from zabbix.history where clock BETWEEN 1648000802 AND 1648004401;
MySQL 提供了 IS NULL 关键字,用来判断字段的值是否为空值(NULL)。空值不同于 0,也不同于空字符串。如果字段的值是空值,则满足查询条件,该记录将被查询出来。如果字段的值不是空值,则不满足查询条件。使用 IS NULL 的基本语法格式如下:
IS [NOT] NULL
案例:使用 IS NULL 关键字来查询 users 表中 url 字段是 NULL 的记录。
select * from zabbix.users where url not null;
案例:使用 IS NULL 关键字来查询 users 表中 url 字段是 不为NULL 的记录。
select * from zabbix.users where url is not null;
注意:IS NULL 是一个整体,不能将 IS 换成“=”。如果将 IS 换成“=”将不能查询出任何结果,数据库系统会出现“Empty set(0.00 sec)”这样的提示。同理,IS NOT NULL 中的 IS NOT 不能换成“!=”或“<>”。
案例:查询每台主机有多少台
# 查询每台主机名称有多少台mysql> select name "主机名",count(*) "数量" from zabbix.hosts where status=0 and name not like '%{%' group by name; +--------------+--------+| 主机名 | 数量 |+--------------+--------+| zbxser01 | 1 || mysql-master | 1 || mysql-db02 | 1 || zbxser02 | 1 || zbxproxy01 | 1 || zbxproxy02 | 1 || zbxproxy04 | 1 || zbxproxy03 | 1 |+--------------+--------+8 rows in set (0.00 sec)
GROUP BY 关键字可以和 GROUP_CONCAT() 函数一起使用。GROUP_CONCAT() 函数会把每个分组的字段值都显示出来。
案例:根据 hosts 表中的 STATUS 字段进行分组查询,使用 GROUP_CONCAT() 函数将每个分组的 NAME 字段的值都显示出来,需要知道每个状态都对应哪些名称的时候,就很有用了
SELECT STATUS,GROUP_CONCAT(NAME) FROM zabbix.hosts WHERE STATUS!=5 GROUP BY STATUS;
由结果可以看到,查询结果分为两组,status 字段值为“0”的是一组,值为“3”的是一组,且每组的主机名或者模板名称都显示出来了。
在数据统计时,GROUP BY 关键字经常和聚合函数一起使用。 聚合函数包括 COUNT(),SUM(),AVG(),MAX() 和 MIN()。其中,COUNT() 用来统计记录的条数;SUM() 用来计算字段值的总和;AVG() 用来计算字段值的平均值;MAX() 用来查询字段的最大值;MIN() 用来查询字段的最小值。
案例:根据 hosts 表的 name 字段进行分组查询,使用 COUNT() 函数计算每一组的记录数
mysql> select name,count(name) from zabbix.hosts where status=0 and name not like '%{%' group by name;+--------------+-------------+| name | count(name) |+--------------+-------------+| zbxser01 | 1 || mysql-master | 1 || mysql-db02 | 1 || zbxser02 | 1 || zbxproxy01 | 1 || zbxproxy02 | 1 || zbxproxy04 | 1 || zbxproxy03 | 1 |+--------------+-------------+
WITH ROLLUP 关键字用来在所有记录的最后加上一条记录,这条记录是上面所有记录的总和,即统计记录数量。
案例:根据 hosts 表中的 name 字段进行分组查询,并使用 WITH ROLLUP 显示记录的总和
mysql> select name,count(name) from zabbix.hosts where status=0 and name not like '%{%' group by name with rollup; +--------------+-------------+| name | count(name) |+--------------+-------------+| mysql-db02 | 1 || mysql-master | 1 || zbxproxy01 | 1 || zbxproxy02 | 1 || zbxproxy03 | 1 || zbxproxy04 | 1 || zbxser01 | 1 || zbxser02 | 1 || NULL | 8 | # 这里就是通过with rollup关键字计算出来的总和
在 MySQL 中,可以使用 HAVING 关键字对分组后的数据进行过滤。 HAVING 关键字和 WHERE 关键字都可以用来过滤数据,且 HAVING 支持 WHERE 关键字中所有的操作符和语法。 但是 WHERE 和 HAVING 关键字也存在以下几点差异:
案例:了解 WHERE 和 HAVING 关键字的相同点和不同点,分别使用 HAVING 和 WHERE 关键字查询出 hosts 表中的name、host、status。SQL 语句和运行结果如下。
# SELECT 关键字后已经查询出了 status 字段,所以 HAVING可用mysql> select name,host,status from zabbix.hosts having status=0;+--------------+--------------+--------+| name | host | status |+--------------+--------------+--------+| zbxser01 | zbxser01 | 0 || {#HV.NAME} | {#HV.UUID} | 0 || {#VM.NAME} | {#VM.UUID} | 0 || mysql-master | mysql-master | 0 || mysql-db02 | mysql-db02 | 0 || zbxser02 | zbxser02 | 0 || zbxproxy01 | zbxproxy01 | 0 || zbxproxy02 | zbxproxy02 | 0 || zbxproxy04 | zbxproxy04 | 0 || zbxproxy03 | zbxproxy03 | 0 |+--------------+--------------+--------+10 rows in set (0.00 sec)# SELECT 关键字后没有 status 字段,所以 HAVING报错了mysql> select name,host from zabbix.hosts having status=0; ERROR 1054 (42S22): Unknown column 'status' in 'having clause'mysql> # SELECT 关键字后没有 status 字段,where是OK的mysql> select name,host from zabbix.hosts where status=0; +--------------+--------------+| name | host |+--------------+--------------+| zbxser01 | zbxser01 || {#HV.NAME} | {#HV.UUID} || {#VM.NAME} | {#VM.UUID} || mysql-master | mysql-master || mysql-db02 | mysql-db02 || zbxser02 | zbxser02 || zbxproxy01 | zbxproxy01 || zbxproxy02 | zbxproxy02 || zbxproxy04 | zbxproxy04 || zbxproxy03 | zbxproxy03 |+--------------+--------------+10 rows in set (0.00 sec)mysql>
因为在 SELECT 关键字后已经查询出了 status 字段,所以 HAVING 和 WHERE 都可以使用。但是如果 SELECT 关键字后没有查询出 status 字段,这时的having就会报错,where是OK的。 由结果可以看出,如果 SELECT 关键字后没有查询出 HAVING 查询条件中使用的 status 字段,MySQL 会提示错误信息:“having子句”中的列“status”未知”。
案例:使用 HAVING 和 WHERE 关键字分别查询status等于0的结果
# 根据hosts表中的status字段进行分组,并通过group_concat将每个分组字段name的内容显示出来,查询全量,不过滤mysql> select status,group_concat(name) from zabbix.hosts group by status\G; *************************** 1. row *************************** status: 0group_concat(name): zbxser01,{#HV.NAME},{#VM.NAME},mysql-master,mysql-db02,zbxser02,zbxproxy01,zbxproxy02,zbxproxy04,zbxproxy03*************************** 2. row *************************** status: 3group_concat(name): Template OS Linux by Zabbix agent,Template App Zabbix Server,Template App Zabbix Proxy,Template Module Zabbix agent,Template OS OpenBSD,Template OS FreeBSD,Template OS AIX,Template OS HP-UX,Template OS Solaris,Template OS Mac OS X,Template OS Windows by Zabbix agent,Template App FTP Service,Template App HTTP Service,Template App HTTPS Service,Template App IMAP Service,Template App LDAP Service,Template App NNTP Service,Template App NTP Service,Template App POP Service,Template App SMTP Service,Template App SSH Service,Template App Telnet Service,Template App Generic Java JMX,Template DB MySQL,Template Server Intel SR1530 IPMI,Template Server Intel SR1630 IPMI,Template VM VMware,Template VM VMware Guest,Template VM VMware Hypervisor,Template Module EtherLike-MIB SNMP,Template Module HOST-RESOURCES-MIB SNMP,Template Module ICMP Ping,Template Module Interfaces Simple SNMP,Template Module Interfaces SNMP,Template Module Interfaces Windows SNMP,Template Module Generic SNMP,Template Net Alcatel Timetra TiMOS SNMP,T*************************** 3. row *************************** status: 5group_concat(name): ,,,3 rows in set, 1 warning (0.00 sec)ERROR: No query specifiedmysql> # 根据hosts表中的status字段进行分组,并通过group_concat将每个分组字段name的内容显示出来,通过having关键字过滤为0的结果mysql> select status,group_concat(name) from zabbix.hosts group by status having status=0;+--------+-------------------------------------------------------------------------------------------------------------+| status | group_concat(name) |+--------+-------------------------------------------------------------------------------------------------------------+| 0 | zbxser01,{#HV.NAME},{#VM.NAME},mysql-master,mysql-db02,zbxser02,zbxproxy01,zbxproxy02,zbxproxy04,zbxproxy03 |+--------+-------------------------------------------------------------------------------------------------------------+1 row in set, 1 warning (0.01 sec)# 根据hosts表中的status字段进行分组,并通过group_concat将每个分组字段name的内容显示出来,通过where关键字过滤为0的结果mysql> select status,group_concat(name) from zabbix.hosts where status=0 group by status;+--------+-------------------------------------------------------------------------------------------------------------+| status | group_concat(name) |+--------+-------------------------------------------------------------------------------------------------------------+| 0 | zbxser01,{#HV.NAME},{#VM.NAME},mysql-master,mysql-db02,zbxser02,zbxproxy01,zbxproxy02,zbxproxy04,zbxproxy03 |+--------+-------------------------------------------------------------------------------------------------------------+1 row in set (0.00 sec)
本文转载于彩虹运维技术栈社区:
https://mp.weixin.qq.com/s/mLerKP2f--8jQjpHuM3ZkQ