MySQL - Having 子句
- MySQL Having 子句
- 带有 ORDER BY 子句的 HAVING 子句
- 带有 COUNT() 函数的 HAVING 子句
- 带有 AVG() 函数的 HAVING 子句
- 带有 MAX() 函数的 HAVING 子句
- 使用客户端程序的 Having 子句
MySQL Having 子句
MySQL HAVING 子句用于过滤分组行根据条件对表进行分组。
此子句与 GROUP BY 子句一起使用,根据一列或多列对行进行分组,然后根据 HAVING 子句中指定的条件对其进行筛选。因此,HAVING 子句必须始终跟在 GROUP BY 子句后面。
由于 WHERE 关键字不能与 COUNT()、SUM()、AVG() 等聚合函数一起使用,因此 MySQL 中添加了 HAVING 子句。
此子句类似于 MySQL 的 WHERE 子句。两者的区别在于,WHERE 子句用于筛选表中的单行数据,而 HAVING 子句则根据条件筛选分组后的行数据。
语法
以下是 MySQL 中 HAVING 子句的基本语法 -
SELECT column1, column2, aggregate_function(column) FROM table_name GROUP BY column1, column2, ... HAVING condition ORDER BY column1, column2, ...;
示例
首先,使用以下查询创建一个名为 CUSTOMERS 的表 -
CREATE TABLE CUSTOMERS ( ID INT NOT NULL, NAME VARCHAR (20) NOT NULL, AGE INT NOT NULL, ADDRESS CHAR (25), SALARY DECIMAL (18, 2), PRIMARY KEY (ID) );
以下 INSERT 语句将 7 条记录插入上述创建的表中 -
INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY) VALUES (1, 'Ramesh', 32, 'Ahmedabad', 2000.00 ), (2, 'Khilan', 25, 'Delhi', 1500.00 ), (3, 'Kaushik', 23, 'Kota', 2000.00 ), (4, 'Chaitali', 25, 'Mumbai', 6500.00 ), (5, 'Hardik', 27, 'Bhopal', 8500.00 ), (6, 'Komal', 22, 'Hyderabad', 4500.00 ), (7, 'Muffy', 24, 'Indore', 10000.00 );
使用以下查询,我们可以验证 CUSTOMERS 表是否已创建 -
SELECT * FROM CUSTOMERS;
以下是 CUSTOMERS 表 -
ID | NAME | AGE | ADDRESS | SALARY |
---|---|---|---|---|
1 | Ramesh | 32 | Ahmedabad | 2000.00 |
2 | Khilan | 25 | Delhi | 1500.00 |
3 | Kaushik | 23 | Kota | 2000.00 |
4 | Chaitali | 25 | Mumbai | 6500.00 |
5 | Hardik | 27 | Bhopal | 8500.00 |
6 | Komal | 22 | Hyderabad | 4500.00 |
7 | Muffy | 24 | Indore | 10000.00 |
HAVING 子句与 ORDER BY 子句
在 MySQL 中,HAVING 子句用于筛选分组,而 ORDER BY 子句用于对结果进行排序。当两者结合使用时,HAVING 子句会先执行,然后根据 ORDER BY 条件对结果集进行排序。
示例
在以下查询中,我们将从 CUSTOMERS 表中检索所有 SALARY 总和小于 4540 的记录,并按姓名升序排列 -
SELECT NAME, SUM(SALARY) as total_salary FROM CUSTOMERS GROUP BY NAME HAVING SUM(SALARY) < 4540 ORDER BY NAME;
输出
上述查询的输出如下所示 -
NAME | total_salary |
---|---|
Kaushik | 2000.00 |
Khilan | 1500.00 |
Komal | 4500.00 |
Ramesh | 2000.00 |
带有 COUNT() 函数的 HAVING 子句
我们可以将 MySQL HAVING 子句与 COUNT() 函数结合使用,根据组包含的行数筛选组。
示例
在此查询中,我们将获取年龄相近的记录数量大于或等于 2。
SELECT AGE FROM CUSTOMERS GROUP BY age HAVING COUNT(age) >= 2;
输出
CUSTOMERS 表中有两条年龄为 25 的记录,因此输出为 25 −
AGE |
---|
25 |
HAVING 子句与 AVG() 函数一起使用
MySQL HAVING 子句也可以与 AVG() 函数一起使用,根据指定列的平均值筛选组。
示例
在下面的查询中,我们尝试返回工资大于 3000 的客户名称 −
SELECT NAME, AVG(salary) as avg_salary FROM customers GROUP BY NAME HAVING AVG(salary) > 3000;
输出
上述查询的输出如下所示 -
NAME | avg_salary |
---|---|
Chaitali | 6500.000000 |
Hardik | 8500.000000 |
Komal | 4500.000000 |
Muffy | 10000.000000 |
带有 MAX() 函数的 HAVING 子句
在 MySQL 中,我们还可以使用带有 MAX() 函数的 HAVING 子句,根据指定列的最大值筛选组。
示例
在此查询中,我们将检索最高 SALARY 小于 4000 的客户名称 -
SELECT NAME, MAX(salary) as max_salary FROM customers GROUP BY NAME HAVING MAX(salary) < 4000;
输出
执行给定查询后,输出显示如下 -
NAME | max_salary |
---|---|
Ramesh | 2000.00 |
Khilan | 1500.00 |
Kaushik | 2000.00 |
使用客户端程序的Having子句
除了使用 MySQL 的 HAVING 子句根据条件过滤表中的分组行之外,我们还可以使用 Node.js、PHP、Java 和 Python 等客户端程序来实现相同的效果。
语法
以下是此操作在各种编程语言中的语法 -
要通过 PHP 程序根据条件过滤表中的分组行,我们需要使用 mysqli 函数 query() 执行带有 HAVING 子句的 SELECT 语句,如下所示 -
$sql = "SELECT EXPRESSION1, EXPRESSION2, ...EXPRESSION_N, AGGREGATE_FUNCTION(EXPRESSION) FROM TABLE_NAME [WHERE CONDITION] GROUP BY EXPRESSION1, EXPRESSION2.. EXPRESSION_N HAVING CONDITION"; $mysqli->query($sql);
要通过 Node.js 程序根据条件筛选表中的分组行,我们需要使用 mysql2 库的 query() 函数执行带有 HAVING 子句的 SELECT 语句,如下所示 -
sql= " SELECT column1, column2, aggregate_function(column) FROM table_name GROUP BY column1, column2, ... HAVING condition ORDER BY column1, column2, ..."; con.query(sql);
要通过 Java 程序根据条件筛选表中的分组行,我们需要使用 JDBC 函数 executeUpdate() 执行带有 HAVING 子句的 SELECT 语句,如下所示 -
String sql = "SELECT column1, column2, aggregate_function(column) FROM table_name GROUP BY column1, column2, ... HAVING condition ORDER BY column1, column2, ..."; statement.executeQuery(sql);
要通过 Python 程序根据条件筛选表中的分组行,我们需要使用 MySQL Connector/Python 的 execute() 函数执行带有 HAVING 子句的 SELECT 语句,如下所示 -
having_clause_query = "SELECT column1, column2, aggregate_function(column) FROM table_name GROUP BY column1, column2 HAVING condition" cursorObj.execute(having_clause_query);
示例
以下是程序 -
$dbhost = 'localhost'; $dbuser = 'root'; $dbpass = 'password'; $dbname = 'TUTORIALS'; $mysqli = new mysqli($dbhost, $dbuser, $dbpass, $dbname); if($mysqli->connect_errno ) { printf("Connect failed: %s
", $mysqli->connect_error); exit(); } //printf('Connected successfully.
'); $sql = 'SELECT tutorial_title, count(tutorial_id) AS tot_count FROM tutorials_tbl WHERE tutorial_id > 1 GROUP BY tutorial_title HAVING count(tutorial_id) > 1'; $result = $mysqli->query($sql); if ($result->num_rows > 0) { printf("Table records: "); while($row = $result->fetch_assoc()) { printf("Title: %s, Count: %d", $row["tutorial_title"], $row["tot_count"]); printf(" "); } } else { printf('No record found.
'); } mysqli_free_result($result); $mysqli->close();
输出
获得的输出如下 -
Table records: Title: Learn MySQL, Count: 2
var mysql = require('mysql2'); var con = mysql.createConnection({ host: "localhost", user: "root", password: "Nr5a0204@123" }); //连接到 MySQL con.connect(function (err) { if (err) throw err; console.log("Connected!"); console.log("--------------------------"); //创建数据库 sql = "create database TUTORIALS" con.query(sql); //选择数据库 sql = "USE TUTORIALS" con.query(sql); //创建表 sql = "CREATE TABLE CUSTOMERS(ID INT NOT NULL,NAME VARCHAR (20) NOT NULL,AGE INT NOT NULL,GENDER VARCHAR (25),SALARY DECIMAL (18, 2),PRIMARY KEY (ID));" con.query(sql); //插入记录 sql = "INSERT INTO CUSTOMERS VALUES(1, 'Ramesh', 25, 'Male', 2000.00),(2, 'Ramesh', 25, 'Male', 1500.00),(3, 'kaushik', 25, 'Female', 2000.00),(4, 'kaushik', 20, 'Male', 6500.00),(5, 'Hardik', 25, 'Male', 8500.00),(6, 'Komal', 20, 'Female', 4500.00),(7, 'Muffy', 25, 'Male', 10000.00);" con.query(sql); //Using HAVING Clause sql = "SELECT NAME, SUM(SALARY) as total_salary FROM CUSTOMERS GROUP BY NAME HAVING SUM(SALARY)输出
生成的输出如下 -
Connected! -------------------------- [ { NAME: 'Komal', total_salary: '4500.00' }, { NAME: 'Ramesh', total_salary: '3500.00' } ]
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class HavingClause { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/TUTORIALS"; String user = "root"; String password = "password"; ResultSet rs; try { Class.forName("com.mysql.cj.jdbc.Driver"); Connection con = DriverManager.getConnection(url, user, password); Statement st = con.createStatement(); //System.out.println("Database connected successfully...!"); String sql = "SELECT NAME, SUM(SALARY) as total_salary FROM CUSTOMERS GROUP BY NAME HAVING SUM(SALARY)输出
获得的输出如下所示 -
Table records: Name: Komal, Total_Salary: 4500.00 Name: Ramesh, Total_Salary: 3500.00
import mysql.connector #建立连接 connection = mysql.connector.connect( host='localhost', user='root', password='password', database='tut' ) # 创建游标对象 cursorObj = connection.cursor() having_clause_query = """SELECT ADDRESS, SUM(SALARY) as total_salary FROM CUSTOMERS GROUP BY ADDRESS HAVING SUM(SALARY)输出
以下是上述代码的输出 -
('Mumbai', Decimal('1200.00'))