数据库之查询语句

Posted 846617819qq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库之查询语句相关的知识,希望对你有一定的参考价值。

一 增语法

1.所有数据按顺序插入
insert [into] 表名 values (值1, ..., 值n)[, ..., (值1, ..., 值n)];
2.指定字段匹配插入,可以任意顺序
insert [into] 表名(字段2, 字段1, ..., 字段n) values (值2, 值1, ..., 值n)[, ..., (值2, 值1, ..., 值n)];
3.插入查询结果
insert [into] 表1(字段1, ..., 字段n) select 字段1, ..., 字段n from 表2 [条件];
# eg: 1
create table t1(
    id int auto_increment,
    x int,
    y int,
    primary key(id)
);
insert t1 values (1, 2, 3), (2, 20, 30); # 按顺序插入
+----+------+------+
| id | x    | y    |
+----+------+------+
|  1 |    2 |    3 |
|  2 |   20 |   30 |
+----+------+------+
#================================================
insert into t1(y, x) values (300, 200); # 按规定字段顺序指定插入
+----+------+------+
| id | x    | y    |
+----+------+------+
|  1 |    2 |    3 |
|  2 |   20 |   30 |
|  3 |  300 |  200 |
+----+------+------+
#================================================
create table nt like t1; # 复制表即完整结构
insert into nt select * from t1; # 复制所有数据
+----+------+------+
| id | x    | y    |
+----+------+------+
|  1 |    2 |    3 |
|  2 |   20 |   30 |
|  3 |  300 |  200 |
+----+------+------+
#================================================
create table tt1(
    x int,
    z int
);
insert into tt1 values (999, 888);
mysql> select * from tt1;
+------+------+
| x    | z    |
+------+------+
|  999 |  888 |
+------+------+
#================================================
insert into nt(x) select x from tt1; # 将tt1中指定字段插入到nt中指定的字段
mysql> select * from nt;
+----+------+------+
| id | x    | y    |
+----+------+------+
|  1 |    2 |    3 |
|  2 |   20 |   30 |
|  3 |  300 |  200 |
|  4 |  999 | NULL |
+----+------+------+
#================================================
insert into nt(x, y) select x,z from tt1; # tt1x及z字段的结果赋值给nt中x,y字段
mysql> select * from nt;
+----+------+------+
| id | x    | y    |
+----+------+------+
|  1 |    2 |    3 |
|  2 |   20 |   30 |
|  3 |  300 |  200 |
|  4 |  999 | NULL |
|  5 |  999 |  888 |
+----+------+------+

二 删语法

1.会记录自增信息,操作会被日志记录,效率低
delete from 表名 [条件];
delete from t1; # 没有条件的情况下是清空所有数据, 但会记录自增信息
insert into t1(x, y) values(6, 66);
+----+------+------+
| id | x    | y    |
+----+------+------+
|  4 |    6 |   66 |
+----+------+------+
#================================================
2.清空表,会重置自增信息
truncate table 表名;
truncate table nt1;
insert into nt1(x, y) values(6, 66);
+----+------+------+
| id | x    | y    |
+----+------+------+
|  1 |    6 |   66 |
+----+------+------+

三 改语法

update 表名 set 字段1=值1[, ..., 字段n=值n] [条件]
insert into tt1 values(111,222),(333,999);
update tt1 set x=666; # 无条件, 全改
+------+------+
| x    | z    |
+------+------+
|  666 |  888 |
|  666 |  222 |
|  666 |  999 |
+------+------+
#============================================
update tt1 set x=777, z=555 where z<888; # 只修改满足条件的行
+------+------+
| x    | z    |
+------+------+
|  666 |  888 |
|  777 |  555 |
|  666 |  999 |
+------+------+

四 查语法

‘‘‘
select [distinct] 字段1 [as 别名], ..., 字段n [as 别名] from [库名.]表名
                    [
                    where 约束条件
                    group by 分组依据
                    having 过滤条件
                    order by 排序的字段
                    limit 限制显示的条数
                    ];
注:
1.查表中所有字段用*表示
2.条件的书写规则严格按照语法顺序书写,可以缺省,但不可以错序
3.约束条件的流程:from -> where -> group by -> having -> distinct -> order by -> limit
4.字段可以起别名
5.字段可以直接做运算 select age + 1 ‘new_age‘ from emp;
6.分组后的条件均可以使用聚合函数
‘‘‘

‘‘‘
3.查询语法的伪代码
def from():
    return "查询的文件"
def where(file):
    return "条件筛选后的结果"
def group_by(res):
    return "分组后的结果"
def having(res):
    return "再次过滤后的结果"
def distinct(res):
    return "去重后的结果"
def order_by(res):
    return "排序后的结果"
def limit(res):
    return "限制条数后的结果"

def select(from=from, where=null, ..., limit=null):
    file = from()
    res = where(file) if where else file
    res = group_by(res) if group_by else res
    ...
    res = limit(res) if limit else res
    
    return res
select(where=where, group_by=group_by)
‘‘‘

常用函数

concat(字段1,...,字段n):完成字段的拼接
concat_ws(x, 字段1,...,字段n):完成字段的拼接,x为连接符
lower():小写
upper():大写
ceil():向上取整
floor():向下取整
round():四舍五入

创建表,插入数据,为上述操作做准备

CREATE TABLE emp  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL,
  `gender` enum(,,未知) NULL DEFAULT 未知,
  `age` int(0) NULL DEFAULT 0,
  `salary` float NULL DEFAULT 0,
  `area` varchar(20) NULL DEFAULT 中国,
  `port` varchar(20) DEFAULT 未知,
  `dep` varchar(20),
  PRIMARY KEY (`id`)
);

INSERT INTO `emp` VALUES 
    (1, yangsir, , 42, 10.5, 上海, 浦东, 教职部),
    (2, engo, , 38, 9.4, 山东, 济南, 教学部),
    (3, jerry, , 30, 3.0, 江苏, 张家港, 教学部),
    (4, tank, , 28, 2.4, 广州, 广东, 教学部),
    (5, jiboy, , 28, 2.4, 江苏, 苏州, 教学部),
    (6, zero, , 28, 8.8, 中国, 黄浦, 咨询部),
    (7, owen, , 28, 8.8, 安徽, 宣城, 教学部),
    (9, ying, , 36, 1.2, 安徽, 芜湖, 咨询部),
    (10, kevin, , 36, 5.8, 山东, 济南, 教学部),
    (11, monkey, , 28, 1.2, 山东, 青岛, 教职部),
    (12, san, , 30, 9.0, 上海, 浦东, 咨询部),
    (13, san1, , 30, 6.0, 上海, 浦东, 咨询部),
    (14, san2, , 30, 6.0, 上海, 浦西, 教学部);    

简单查询

select concat(area, -, port) as 家乡 from emp; # 上海-浦东... 属于 起的别名 家乡 列
+------------------+
| 家乡             |
+------------------+
| 上海-浦东        |
| 山东-济南        |
| 江苏-张家港      |
| 广州-广东        |
| 江苏-苏州        |
| 中国-黄浦        |
| 安徽-宣城        |
| 安徽-芜湖        |
| 山东-济南        |
| 山东-青岛        |
| 上海-浦东        |
| 上海-浦东        |
| 上海-浦西        |
+------------------+
#===============================================
select concat_ws("-", name, area, port) 信息 from emp; # 以"-"字符拼接后面的所有字段
+------------------------+
| 信息                   |
+------------------------+
| yangsir-上海-浦东      |
| engo-山东-济南         |
| jerry-江苏-张家港      |
| tank-广州-广东         |
| jiboy-江苏-苏州        |
| zero-中国-黄浦         |
| owen-安徽-宣城         |
| ying-安徽-芜湖         |
| kevin-山东-济南        |
| monkey-山东-青岛       |
| san-上海-浦东          |
| san1-上海-浦东         |
| san2-上海-浦西         |
+------------------------+
#===============================================
select upper(name) name, gender, age from emp; # 可以指定多个字段
+-------------+--------+------+
| upper(name) | gender | age  |
+-------------+--------+------+
| YANGSIR     | 男     |   42 |
| ENGO        | 男     |   38 |
| JERRY       | 女     |   30 |
| TANK        | 女     |   28 |
| JIBOY       | 男     |   28 |
| ZERO        | 男     |   28 |
| OWEN        | 男     |   28 |
| YING        | 女     |   36 |
| KEVIN       | 男     |   36 |
| MONKEY      | 女     |   28 |
| SAN         | 男     |   30 |
| SAN1        | 男     |   30 |
| SAN2        | 男     |   30 |
+-------------+--------+------+
#===============================================
select name, ceil(salary), floor(salary), round(salary) from emp where name=kevin; # 数学函数
+-------+--------------+---------------+---------------+
| name  | ceil(salary) | floor(salary) | round(salary) |
+-------+--------------+---------------+---------------+
| kevin |            6 |             5 |             6 |
+-------+--------------+---------------+---------------+
#===============================================
# 去重前提: 所查所有字段的综合结果完全相同, 才认为是重复的, 只保留重复中的一行数据
select distinct area from emp;
+--------+
| area   |
+--------+
| 上海   |
| 山东   |
| 江苏   |
| 广州   |
| 中国   |
| 安徽   |
+--------+
#===============================================
select distinct area, port from emp;
+--------+-----------+
| area   | port      |
+--------+-----------+
| 上海   | 浦东      |
| 山东   | 济南      |
| 江苏   | 张家港    |
| 广州   | 广东      |
| 江苏   | 苏州      |
| 中国   | 黄浦      |
| 安徽   | 宣城      |
| 安徽   | 芜湖      |
| 山东   | 青岛      |
| 上海   | 浦西      |
+--------+-----------+
#===============================================

where

1.比较运算符
= | < | > | <= | >= | !=
select * from emp where area!="上海";
+----+--------+--------+------+--------+--------+-----------+-----------+
| id | name   | gender | age  | salary | area   | port      | dep       |
+----+--------+--------+------+--------+--------+-----------+-----------+
|  2 | engo   | 男     |   38 |    9.4 | 山东   | 济南      | 教学部    |
|  3 | jerry  | 女     |   30 |      3 | 江苏   | 张家港    | 教学部    |
|  4 | tank   | 女     |   28 |    2.4 | 广州   | 广东      | 教学部    |
|  5 | jiboy  | 男     |   28 |    2.4 | 江苏   | 苏州      | 教学部    |
|  6 | zero   | 男     |   28 |    8.8 | 中国   | 黄浦      | 咨询部    |
|  7 | owen   | 男     |   28 |    8.8 | 安徽   | 宣城      | 教学部    |
|  9 | ying   | 女     |   36 |    1.2 | 安徽   | 芜湖      | 咨询部    |
| 10 | kevin  | 男     |   36 |    5.8 | 山东   | 济南      | 教学部    |
| 11 | monkey | 女     |   28 |    1.2 | 山东   | 青岛      | 教职部    |
+----+--------+--------+------+--------+--------+-----------+-----------+
#==============================================
2.区间运算符
between 10 and 20:10~20
in(10, 20, 30):10或20或30
select * from emp where id between 3 and 5; # [3, 5], 闭合区间,包含3和5, 三行数据 
+----+-------+--------+------+--------+--------+-----------+-----------+
| id | name  | gender | age  | salary | area   | port      | dep       |
+----+-------+--------+------+--------+--------+-----------+-----------+
|  3 | jerry | 女     |   30 |      3 | 江苏   | 张家港    | 教学部    |
|  4 | tank  | 女     |   28 |    2.4 | 广州   | 广东      | 教学部    |
|  5 | jiboy | 男     |   28 |    2.4 | 江苏   | 苏州      | 教学部    |
+----+-------+--------+------+--------+--------+-----------+-----------+
#==============================================
select * from emp where id in(2, 4, 6, 8, 10, 12, 14, 16, 18); # 分离的区间,2,4,6,8,10,12,14都会被显示
+----+-------+--------+------+--------+--------+--------+-----------+
| id | name  | gender | age  | salary | area   | port   | dep       |
+----+-------+--------+------+--------+--------+--------+-----------+
|  2 | engo  | 男     |   38 |    9.4 | 山东   | 济南   | 教学部    |
|  4 | tank  | 女     |   28 |    2.4 | 广州   | 广东   | 教学部    |
|  6 | zero  | 男     |   28 |    8.8 | 中国   | 黄浦   | 咨询部    |
| 10 | kevin | 男     |   36 |    5.8 | 山东   | 济南   | 教学部    |
| 12 | san   | 男     |   30 |      9 | 上海   | 浦东   | 咨询部    |
| 14 | san2  | 男     |   30 |      6 | 上海   | 浦西   | 教学部    |
+----+-------+--------+------+--------+--------+--------+-----------+
#==============================================
3.逻辑运算符
and | or | not
select * from emp where area="山东" and port="济南";
+----+-------+--------+------+--------+--------+--------+-----------+
| id | name  | gender | age  | salary | area   | port   | dep       |
+----+-------+--------+------+--------+--------+--------+-----------+
|  2 | engo  | 男     |   38 |    9.4 | 山东   | 济南   | 教学部    |
| 10 | kevin | 男     |   36 |    5.8 | 山东   | 济南   | 教学部    |
+----+-------+--------+------+--------+--------+--------+-----------+
#==============================================
4.相似运算符
like _owen%:模糊匹配字符串owen,_表示一个字符,%表示任意字符
# 匹配的字段为en,想得到的结果为owen
select * from emp where name like __en%; # 在en前可以出现2个任意字符, 之后可以出现0或多个任意字符
+----+------+--------+------+--------+--------+--------+-----------+
| id | name | gender | age  | salary | area   | port   | dep       |
+----+------+--------+------+--------+--------+--------+-----------+
|  7 | owen | 男     |   28 |    8.8 | 安徽   | 宣城   | 教学部    |
+----+------+--------+------+--------+--------+--------+-----------+

正则表达式

# why: like完成模糊匹配, 但功能局限, 可以模糊个数, 但不能模糊类型, 正则可以完成类型及个数的模糊匹配
‘‘‘
语法:字段 regexp ‘正则表达式‘
注:只支持部分正则语法

需求:查找姓名有数字的员工信息
select * from emp where name regexp‘.*[0-9]+.*‘;
+----+------+--------+------+--------+--------+--------+-----------+
| id | name | gender | age  | salary | area   | port   | dep       |
+----+------+--------+------+--------+--------+--------+-----------+
| 13 | san1 | 男     |   30 |      6 | 上海   | 浦东   | 咨询部    |
| 14 | san2 | 男     |   30 |      6 | 上海   | 浦西   | 教学部    |
+----+------+--------+------+--------+--------+--------+-----------+

group by 分组

分组:根据字段相同值形成不同的类别,不明确分组其实整个表就为一个默认大组
原因:把以值共性得到的类别作为考虑单位,不再关系单条记录,而且一组记录

结果:只能考虑组内多条数据的聚会结果(聚合函数结果),分组的字段同样是聚合结果,如:组内的最大最小值
配置文件中加入此数据,mysql模式为安全模式,并且分组不正确时无法分
sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

聚合函数:
max():最大值
min():最小值
avg():平均值
sum():和
count():记数
group_concat():组内字段拼接,用来查看组内其他字段

eg:1
每个部门的平均薪资
select dep, avg(salary) 平均薪资 from emp group by dep;
+-----------+-------------------+
| dep       | avg(salary)       |
+-----------+-------------------+
| 咨询部    | 6.250000059604645 |
| 教学部    | 5.400000027247837 |
| 教职部    | 5.850000023841858 |
+-----------+-------------------+
#===============================================
eg:2
每个部门都有哪些人
select dep, group_concat(name) from emp group by dep;
+-----------+---------------------------------------+
| dep       | group_concat(name)                    |
+-----------+---------------------------------------+
| 咨询部    | san1,san,ying,zero                    |
| 教学部    | san2,kevin,owen,jiboy,tank,jerry,engo |
| 教职部    | monkey,yangsir                        |
+-----------+---------------------------------------+
#===============================================
需求:
各性别中附属于教学部的最高薪资
select max(salary) 最高薪资, gender from emp where dep=教学部 group by gender;
+--------------+--------+
| 最高薪资     | gender |
+--------------+--------+
|          9.4 | 男     |
|            3 | 女     |
+--------------+--------+
#===============================================
思考:
想知道需求中员工的姓名 => 子查询
上方结果: 男的最高薪资对应的人名, 女的最高薪资对应的人名
# select group_concat(name), max(salary) ‘最高薪资‘, gender from emp where dep=‘教学部‘ group by gender; 错误
+----------------------------+-------------------+--------+
| group_concat(name)         | 最高薪资          | gender |
+----------------------------+-------------------+--------+
| engo,jiboy,owen,kevin,san2 | 9.399999618530273 | 男     |
| jerry,tank                 |                 3 | 女     |
+----------------------------+-------------------+--------+
#===============================================
1. 14条数据部门有3个, 并且每个部分有多条记录, 可以作为分组依据, 同理, 性别也可以
# select * from emp group by dep; # 非分组安全模式下, 可以查询非聚合结果, 显示的是第一条记录, 没有意义, 分组安全模式下不能查询非聚合结果的字段
select dep from emp group by dep;
+-----------+
| dep       |
+-----------+
| 咨询部    |
| 教学部    |
| 教职部    |
+-----------+
#===============================================
2. 如果就像以姓名进行分组, 可以, 但没多大意义, 原因name值基本上都不相同, 以组考虑会导致组内大多只要一条记录(自成一组), 组的利用就不是很强烈, 此类分组是无意义的
select name from emp group by name; # 可以分组, 意义不大
+---------+
| name    |
+---------+
| engo    |
| jerry   |
| jiboy   |
| kevin   |
| monkey  |
| owen    |
| san     |
| san1    |
| san2    |
| tank    |
| yangsir |
| ying    |
| zero    |
+---------+
#===============================================
考虑的三个问题: 以什么分组(相同数据较多的字段) 分组后的考虑单位(组并非组内的每一条记录) 可以查询的结果(当前分组的字段及聚合函数形成的聚合结果)

解决分组中思考题的过程

# res = select max(salary) ‘最高薪资‘, gender from emp where dep=‘教学部‘ group by gender;
# select name from emp where (salary 跟 res作比较)
# 一个查询依赖于另一个查询的结果 => 一个查询的结果作为另外一个查询的条件 => 子查询

子查询

子查询:将一条查询结果作为另外一条查询的条件
语法:一条select语句用()包裹得到的结果作为另一条select语句的条件
# 伪sql: select * from emp where salary =|in (select salary from emp where 条件)

单行子查询:
子查询语句的结果为一行数据,可以结合 = | < | > | <= | >= | != 运算符来完成父查询
select salary from emp where salary > 10; # => 作为子查询
# 查询姓名,性别.地区,基于薪资大于10的结果的查询结果

eg: 1
select name, gender, area from emp where salary = (select salary from emp where salary > 10);

多行子查询:
子查询语句的结果为多行数据,可以结合 in | all | any 运算符来完成父查询
in:任意单一值,一次只能考虑子查询中的一个结果
all:全部值,将子查询结果作为一个整体考虑
any:任意多个值:子查询的每一个结果都可以作为参考依据

eg: 2
# 子查询的结果 (9.4, 3)
select name from emp where salary in (select max(salary) 最高薪资 from emp where dep=教学部 group by gender);
# 遍历14条数据, 14条数据的salary在(9.4, 3)区域中,就可以完成匹配, 结果为两条(9.4和3那两条)

select * from emp where salary < all(select max(salary) 最高薪资 from emp where dep=教学部 group by gender);
# 遍历14条数据, salary要小于(9.4, 3)中的每一个, 反映就是小于3, 结果为薪资1.2,2.4的那四条数据

select * from emp where salary > any(select max(salary) 最高薪资 from emp where dep=教学部 group by gender);
# 遍历14条数据, salary大于9.4或大于3的数据均满足条件, 结果就是刨除小于等于3的那几条数据

having 筛选

‘‘‘
why:完成在分组之后的筛选
注意:having条件是实现聚合结果层面上的筛选 => 拿聚会结果完成判断

需求:
1.各部门的平均薪资
select dep, avg(salary) ‘平均薪资‘ from emp group by dep;

2.平均薪资大于6w的部门(部门与部门的平均薪资)
解决: 以dep进行分组, 以avg(salary)作为判断条件(筛选)
select dep, avg(salary) ‘平均薪资‘ from emp group by dep having avg(salary) > 6;

# 总结: having通过聚合函数结果完成筛选
select max(salary) from emp having max(salary) > 9.4;
# 虽然没有明确书写group by, 但在having中使用了聚合函数,所以该查询就将整个表当做一个默认大表来考虑,所以查询的字段只能为聚合函数的结果
‘‘‘

order by 排序

‘‘‘
why:完成排序
注意:可以使用聚合函数,哪怕没有明确group by

升序 | 降序:asc | desc
eg:order by age desc => 按照年龄降序
select * from emp order by age desc;


需求:
将部门按照部门平均工资降序方式排序
select dep, avg(salary) from emp group by dep order by avg(salary) desc;
‘‘‘

limit 限制

‘‘‘
why:限制最终结果的数据行数
注意:limit只与数字结合使用

应用:
limit 1:只能显示一行数据
limit 6,5:从第6+1行开始显示5条数据(索引从0开始)

select * from emp limit 1;
select * from emp limit 6,5;

需求:
获得薪资最高的人的一条信息
select * from emp order by salary desc limit 1;
‘‘‘

 

以上是关于数据库之查询语句的主要内容,如果未能解决你的问题,请参考以下文章

JDBC操作数据库之查询数据

[AndroidStudio]_[初级]_[配置自动完成的代码片段]

[AndroidStudio]_[初级]_[配置自动完成的代码片段]

[AndroidStudio]_[初级]_[配置自动完成的代码片段]

oracle 语句之对数据库的表名就行模糊查询,对查询结果进行遍历,依次获取每个表名结果中的每个字段

SQL语句之查询(SELECT)