最近公司要实现一个通过年月来查询每个月的挂号统计(当日挂号,预约挂号),因为医院每个月都要来问我们这边一次,每次都去数据库查询太麻烦了,所以就需要开发一个查询挂号统计的接口。
前面用了很多种方法,要不就是数据不对,要不就是行不通
最后才决定使用聚合函数加上条件语句
SELECT LEFT(create_date,7) AS `yearMonth`,
SUM(CASE WHEN isday = 1 THEN 1 ELSE 0 END) AS drghCount,
SUM(CASE WHEN isday = 0 THEN 1 ELSE 0 END) AS yyghCount
FROM
toregister
WHERE
LEFT(create_date,7) BETWEEN '2022-01'
AND '2022-12'
GROUP BY
LEFT(create_date,7)
LEFT 函数是 SQL 中常用的字符串函数,用于截取一个字符串的左边若干个字符,并返回截取到的字符串。
LEFT 函数的语法如下:
LEFT(string, length)
其中,string 表示要截取的字符串,length 表示要截取的字符长度。LEFT 函数将字符串 string 截取到 length 字符长度,返回截取后的字符串。
示例:
SELECT LEFT('Hello, World!', 5);
返回结果为 “Hello”,因为该函数将 “Hello, World!” 这个字符串的左边 5 个字符 “Hello” 进行截取。
上面SQL中的 LEFT(create_date,7)
就是用来截取 toregister 表中的 create_date
字段,截取的起始位置是 0
,截取的长度是 7
,表示将 create_date
字段按年月的格式进行展示,格式类似 2021-05
。
MySQL的CASE函数可以根据条件表达式返回不同的结果。它类似于其他程序语言中的switch或if/else语句。CASE函数有两种语法形式:简单CASE函数和搜索CASE函数。
CASE case_expr
WHEN when_expr1 THEN result1
WHEN when_expr2 THEN result2
...
ELSE else_result
END
其中 case_expr
是要测试的表达式,when_expr1, when_expr2, ...
是不同的条件表达式,result1, result2, ...
是当条件表达式为真时要返回的结果,else_result
是所有条件表达式都不为真时要返回的结果。
下面是一个简单CASE函数的示例:
SELECT score,
CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B'
WHEN score >= 70 THEN 'C'
WHEN score >= 60 THEN 'D'
ELSE 'F'
END AS grade
FROM student_score;
在这个示例中,我们使用了一个简单CASE函数来根据分数计算出一个等级。如果分数大于等于90,等级就是A,如果分数大于等于80,等级是B,以此类推。如果分数低于60,等级是F。我们还给这个结果集中的等级列起了一个别名叫做“grade”。
接下来是搜索CASE函数的语法形式:
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
ELSE else_result
END
其中 condition1, condition2, ...
是用来测试的条件表达式,与简单CASE函数的 when_expr1, when_expr2, ...
相似。当一个条件表达式(condition1
, condition2
, …)为 TRUE 时,对应的 result1
, result2
, … 就会被返回。与简单CASE函数不同的是,搜索CASE函数不需要一个测试表达式,它只需要一系列条件表达式和结果。
下面是一个搜索CASE函数的示例:
SELECT grade,
CASE
WHEN grade LIKE 'A%' THEN 'Excellent'
WHEN grade LIKE 'B%' THEN 'Good'
WHEN grade LIKE 'C%' THEN 'Fair'
WHEN grade LIKE 'D%' THEN 'Poor'
ELSE 'Failing'
END AS result
FROM grades;
在这个示例中,我们使用了一个搜索CASE函数来给每个等级(比如A、B、C、D和F)赋一个结果(比如“Excellent”、“Good”、“Fair”、“Poor”和“Failing”)。如果等级以A开头,结果就是“Excellent”,以此类推。我们还给这个结果集中的结果列起了一个别名叫做“result”。
上面SQL中的 CASE WHEN isday = 0 THEN 1 ELSE 0 END
就是当isday这个字段的值等于0
时这时候对应的值就是1
,否则为0
。
SUM 函数规则:
SUM 函数的语法如下:
select SUM(column_name) from table_name
其中,column_name 是一个列或一个表达式,可以是常量、字段或其他函数的组合,table_name为要从中检索的表名。SUM 函数的执行步骤如下:
例如,假设有一个存储销售数据的表 Sales,表结构如下:
Sales (id, product_name, sales_amount, sales_date)
要计算所有销售额的总和,可以使用下面的 SQL 语句:
SELECT SUM(sales_amount)
FROM Sales;
上面SQL中SUM(CASE WHEN isday = 1 THEN 1 ELSE 0 END) AS drghCount,SUM(CASE WHEN isday = 0 THEN 1 ELSE 0 END) AS yyghCount
就是统计当日挂号和预约挂号的总数的。
GROUP BY是一种SQL函数,通常与聚合函数(如SUM、COUNT、AVG等)一起使用,以对数据库表的数据进行分组并进行统计计算。
语法格式如下:
SELECT 列1, 列2, 聚合函数列3
FROM 表名
GROUP BY 列1, 列2
注意: 在使用GROUP BY时,除聚合函数列外,所有选定列都必须在GROUP BY子句中出现,如果列中只有聚合函数而没有普通列就不需要使用GROUP BY函数
如果要按产品名称和销售日期汇总销售额,可以使用 GROUP BY 子句,如下:
SELECT product_name, sales_date, SUM(sales_amount)
FROM Sales
GROUP BY product_name, sales_date;
上述语句将按产品名称和销售日期分组统计相应的销售额。
上面SQL中GROUP BY LEFT(create_date,7)
根据创建的时间年月来进行分组
SELECT LEFT(create_date,7) AS `yearMonth`,
SUM(CASE WHEN isday = 1 THEN 1 ELSE 0 END) AS drghCount,
SUM(CASE WHEN isday = 0 THEN 1 ELSE 0 END) AS yyghCount
FROM
toregister
WHERE
LEFT(create_date,7) BETWEEN '2022-01'
AND '2022-12'
GROUP BY
LEFT(create_date,7)
上述SQL解释起来就是
1.先查询挂号表toregister
2.然后在执行WHERE条件语句,再使用LEFT(create_date,7)
将创建时间中的年-月截取出来,使用BETWEEN条件进行数据筛选
3.再使用GROUP BY
分组函数对LEFT(create_date,7)
年-月进行分组
4.进行聚合函数的计算SUM(CASE WHEN isday = 1 THEN 1 ELSE 0 END) AS drghCount
先执行里面的条件语句:如果isday=1那么对应的值就为1
,
否则为0
(因为当日挂号的值我们设置的是1
,预约挂号的值是0
);SUM(CASE WHEN isday = 0 THEN 1 ELSE 0 END) AS yyghCount
这个与前面的那个相反。
5.最后查询出select 里面的列,第一个参数使用LEFT(create_date,7)
将创建时间中的年-月截取出来
HAVING是SQL中用于对分组查询结果进行筛选的关键词。在使用GROUP BY对数据进行分组后,我们可以使用HAVING来进行条件过滤,只保留满足条件的分组数据。
例如,以下SQL查询语句可以获取每个部门中工资总额大于10000的员工数量和平均工资:
SELECT dept_id, COUNT(*) AS num_employees, AVG(salary) AS avg_salary
FROM employees
GROUP BY dept_id
HAVING SUM(salary) > 10000;
该查询首先使用GROUP BY对employees表中的数据按照dept_id进行了分组,然后使用HAVING对分组数据进行了过滤,只保留工资总额大于10000的数据。最终,查询结果返回了每个部门中工资总额大于10000的员工数量和平均工资。
竟然上面已经介绍了这么多了,不如我们把聚合函数也介绍了吧。
sum函数已经描述过了,这里就不做赘述了
以下是聚合函数的一些常见规则:
创建一张学生表用于后面的学习,以下的 SQL 语句创建一个名为 students 的表,其中包含 id、name、age 和 score 四个列:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `students`;
CREATE TABLE `students` (
`id` int(0) NOT NULL,
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`age` int(0) NULL DEFAULT NULL,
`score` int(0) NULL DEFAULT NULL,
`grade` int(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
新增学生表数据
INSERT INTO `students` VALUES (1, 'Tom', 16, 85, 1);
INSERT INTO `students` VALUES (2, 'Jack', 15, 90, 1);
INSERT INTO `students` VALUES (3, 'Alice', 18, 78, 2);
INSERT INTO `students` VALUES (4, 'Bob', 19, 95, 3);
INSERT INTO `students` VALUES (5, 'Jenny', 18, 80, 3);
INSERT INTO `students` VALUES (6, 'David', 17, 82, 2);
INSERT INTO `students` VALUES (7, 'Helen', 17, 89, 1);
INSERT INTO `students` VALUES (8, 'Peter', 18, 75, 2);
SET FOREIGN_KEY_CHECKS = 1;
这里的年级就代表高中的一二三年级吧。
AVG函数规则:
AVG函数的语法如下:
SELECT AVG(column_name) FROM table_name;
其中,column_name为要计算平均值的列名,table_name为要从中检索的表名。
SELECT s.grade,AVG(s.score) AS score FROM students s GROUP BY s.grade
SELECT AVG(s.score) AS score FROM students s
SELECT s.age,AVG(s.score) AS score FROM students s GROUP BY s.age
count函数规则:
COUNT函数的语法如下:
SELECT COUNT(column_name) FROM table_name WHERE condition;
其中,column_name是指定要统计的列名,table_name是指定的表名,condition是选取的条件语句。
SELECT s.grade,COUNT(1) AS nums FROM students s GROUP BY s.grade
SELECT s.age,COUNT(1) AS nums FROM students s GROUP BY s.age
SELECT s.grade,COUNT(1) AS nums FROM students s WHERE s.score > 80 GROUP BY s.grade
MAX函数规则:
MAX函数的语法如下:
SELECT MAX(column_name) FROM table_name;
其中,column_name为要计算最大值的列名,table_name为要从中检索的表名。
SELECT grade, MAX(score) AS max_score, name
FROM students
WHERE (grade, score) IN (
SELECT grade, MAX(score)
FROM students
GROUP BY grade
)
GROUP BY grade, name;
SELECT grade, MAX(age) AS max_age, name
FROM students
WHERE (grade, age) IN (
SELECT grade, MAX(age)
FROM students
GROUP BY grade
)
GROUP BY grade,name;
MIN函数规则:
MIN函数的语法如下:
SELECT MIN(column_name) FROM table_name;
其中,column_name为要计算最小值的列名,table_name为要从中检索的表名。
SELECT grade, MIN(score) AS min_score, name
FROM students
WHERE (grade, score) IN (
SELECT grade, MIN(score)
FROM students
GROUP BY grade
)
GROUP BY grade,name;
SELECT grade, MIN(age) AS min_age, name
FROM students
WHERE (grade, age) IN (
SELECT grade, MIN(age)
FROM students
GROUP BY grade
)
GROUP BY grade,name;
GROUP_CONCAT函数的规则:
GROUP_CONCAT函数的语法如下:
GROUP_CONCAT函数的语法通常如下:
GROUP_CONCAT([DISTINCT] expression [ORDER BY clause] [SEPARATOR 'separator'])
其中,关键字和参数的含义如下:
[DISTINCT]
:可选项,表示对拼接结果进行去重处理。expression
:要进行拼接的表达式或列名。[ORDER BY clause]
:可选项,用于对拼接结果进行排序。可以指定排序的列名,也可以使用表达式。[SEPARATOR 'separator']
:可选项,指定用于分隔拼接结果的符号或字符串,如果不指定,则默认使用逗号(,)作为分隔符。SELECT GROUP_CONCAT(s.name) AS names FROM students s
SELECT GROUP_CONCAT(CONCAT(s.grade,'-',s.name,'-',s.age,'-',s.score) SEPARATOR '|') AS student_info FROM students s
CONCAT函数用于将多个字符串连接成一个字符串。它是一种常用的字符串函数,在不同的编程语言和数据库中有不同的语法。
SQL(结构化查询语言):
CONCAT(string1, string2, ...)
SELECT GROUP_CONCAT(s.score ORDER BY s.score ASC) AS scores FROM students s
SELECT GROUP_CONCAT(DISTINCT s.age ORDER BY s.age DESC SEPARATOR ';') AS ages FROM students s
在这之前,我们先多添加几条数据,以方便后面的问题
INSERT INTO students (id, name, age, score, grade)
SELECT (SELECT MAX(id) FROM students) + 1, 'Amy', 16, 90, 1 UNION ALL
SELECT (SELECT MAX(id) FROM students) + 2, 'Michael', 15, 85, 1 UNION ALL
SELECT (SELECT MAX(id) FROM students) + 3, 'Sophia', 19, 82, 2 UNION ALL
SELECT (SELECT MAX(id) FROM students) + 4, 'Daniel', 18, 92, 2 UNION ALL
SELECT (SELECT MAX(id) FROM students) + 5, 'Jessica', 17, 88, 1 UNION ALL
SELECT (SELECT MAX(id) FROM students) + 6, 'Kevin', 18, 95, 3 UNION ALL
SELECT (SELECT MAX(id) FROM students) + 7, 'Lily', 17, 83, 3 UNION ALL
SELECT (SELECT MAX(id) FROM students) + 8, 'Ryan', 16, 87, 2 UNION ALL
SELECT (SELECT MAX(id) FROM students) + 9, 'Mia', 19, 90, 1 UNION ALL
SELECT (SELECT MAX(id) FROM students) + 10, 'Jacob', 17, 80, 3;
SELECT COUNT(1) FROM students s GROUP BY s.grade; #求每个年级的学生数量
每个年级的学生数量
最终实现,使用子查询先将每个年级的学生数量查询出来,然后在使用AVG函数进行求平均值,然后在筛选学生数量大于平均学生数量的年级。
SELECT
s.grade,
COUNT( 1 ) AS nums
FROM
students s
GROUP BY
s.grade
HAVING
nums > (
SELECT
AVG( nums1 )
FROM
( SELECT COUNT( 1 ) AS nums1 FROM students s GROUP BY s.grade ) s2)
先使用子查询将分数进行分段
SELECT r.rate,COUNT(rate) AS nums FROM (SELECT CASE
WHEN s.score BETWEEN 60 AND 80 THEN "及格"
WHEN s.score BETWEEN 81 AND 90 THEN "良好"
WHEN s.score BETWEEN 91 AND 100 THEN "优秀"
ELSE "不及格"
END AS rate FROM students s ) r
GROUP BY r.rate
ORDER BY nums DESC
这个问题与问题一类似,就不做赘述了。
SELECT
age,
COUNT( age ) AS nums
FROM
students
GROUP BY
age
HAVING
nums = (
SELECT
MAX( nums1 )
FROM
( SELECT COUNT( age ) AS nums1 FROM students GROUP BY age ) AS s1)