基础sql
SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL。
数据查询语言DQL
数据查询语言DQL基本结构是由SELECT相关的查询语句
语法规则:
SELECT <字段名表>
FROM <表或视图名>
WHERE <查询条件>
普通查询
select * [or 字段名] from 表名 [where 条件];
select * from user where id < 10;
特殊查询,给查出的结果赋予自己给的值,用于后续的操作
select 1 as id,'苏苏' as name,phone_no from user where id=10;
多表查询:
select a.phone,b.name from user a ,user_detail b limit 3;
注意:当where中的字段非整型时,需要将要查询的条件加上引号,eg phone=’188********‘
数据操纵语言DML
数据操纵语言DML主要有三种形式:
- 插入:INSERT
INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
INSERT INTO `test_A` (`id`, `name`, `id_no`, `sex`) VALUES (55, '12', '111', '1');
- 更新:UPDATE
UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
update `user_detail` set name='梅长苏' where id=2;
- 删除:DELETE
truncate:清空表记录但不删除表结构,删除内容,释放空间,但不删除定义。
truncate table user;
delete 表记录与结构一起删除,但是不删除定义,也不释放空间
DELETE FROM 表名称 WHERE 列名称 = 值
delete from user;
drop 删除内容和定义,释放空间。(表结构和数据一同删除)
drop table user;
很棒的参考文章:https://www.cnblogs.com/zhizhao/p/7825469.html
数据定义语言DDL
数据定义语言DDL用来创建数据库中的各种对象(表|视图|索引|同义词|聚簇等)[CREATE TABLE/VIEW/INDEX/SYN/CLUSTER],其实就是我们在创建表的时候用到的一些sql,比如说:CREATE、ALTER、DROP等。DDL主要是用在定义或改变表的结构,数据类型,表之间的链接和约束等初始化工作上「表|视图|索引|同义词簇DDL操作是隐性提交的!不能rollback 」
CREATE TABLE 表名称
(
列名称1 数据类型,
列名称2 数据类型,
列名称3 数据类型,
....
)
建库:create database test;
建表:
CREATE TABLE `test_A` (
`id` bigint(20) not null AUTO_INCREMENT, # 自增
`name` varchar(50) DEFAULT '' COMMENT '姓名', # 如果没有值,默认为空
`id_no` varchar(32) DEFAULT '' COMMENT '证件号',
`sex` varchar(32) DEFAULT '' COMMENT '性别',
PRIMARY KEY (`id`), # 主键
UNIQUE KEY `uni_idx_id_no` (`id_no`) # id_no在表中是唯一的
)ENGINE=InnoDB AUTO_INCREMENT=50 DEFAULT CHARSET=utf8 COMMENT='测试' ; # 设置起始id及表的备注
ALTER TABLE table_name
ALTER COLUMN column_name datatype
DROP TABLE 表名称
DROP DATABASE 数据库名称
数据控制语言DCL
数据控制语言DCL用来授予或回收访问数据库的某种特权,并控制
数据库操纵事务发生的时间及效果,对数据库实行监视等。
1) GRANT:授权。
2) ROLLBACK [WORK] TO [SAVEPOINT]:回退到某一点。
回滚---ROLLBACK
回滚命令使数据库状态回到上次最后提交的状态。其格式为:
SQL>ROLLBACK;
3) COMMIT [WORK]:提交。
初步进阶sql
- 数据库连接(join)与嵌套查询
1.内连接
概念:内联接是用比较运算符比较要联接列的值的联接
SELECT … FROM join_table
[INNER] JOIN join_table2
[ON join_condition]
WHERE where_definition
只列出这些连接表中与连接条件相匹配的数据行。join 或 inner join,INNER可以不写,则默认为内连接。[ON join_condition]里面写的是连接的条件。注释:**只返回符合条件的table1和table2的列**
2.外连接
外连接分类:
SELECT … FROM join_table1
(LEFT | RIGHT | FULL) [OUTER] JOIN join_table2
ON join_condition
WHERE where_definition
其中,[OUTER]部分可以不写,(LEFT | RIGHT | FULL)部分要写其中一个。
左外连接(LEFT [OUTER] JOIN)
左外连接:左表列出全部,右表只列出匹配的记录。
(1)左向外联接的结果集包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值(null)。
(2)sql 语句
select * from table1 left join table2 on table1.id=table2.id
注释:包含table1的所有子句,根据指定条件返回table2相应的字段,不符合的以null显示
右外连接(RIGHT [OUTER] JOIN)
右外连接:右表列出全部,左表只列出匹配的记录。
右连接:right join 或 right outer join
(1)右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。
(2)sql 语句
select * from table1 right join table2 on table1.id=table2.id
注释:包含table2的所有子句,根据指定条件返回table1相应的字段,不符合的以null显示
交叉连接(CROSS JOIN)
交叉连接:
SELECT … FROM join_table1 CROSS JOIN join_table2;
没有ON子句和WHERE子句,它返回的是连接表中所有数据行的笛卡尔积。笛卡尔积举例:假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}
注:cross join后加条件只能用where,不能用on
等价于:SELECT … FROM table1, table2;
完整外部联接/全外连接(FULL [OUTER] JOIN)
(1)完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。**如果表之间有匹配行,则整个结果集行包含基表的数据值。**
(2)sql 语句
select * from table1 full join table2 on table1.id=table2.id
**注释:返回左右连接的和(见上左、右连接)**
3.子查询
外查询的条件是子查询的结果
select amount,term from table_A where contract_loan_amount=(select max(amount) from table_A);
- 排序order by
asc 正序 desc倒序 limit 取多少条数据,经常一起使用
select * from user order by id asc limit 10;
select * from user order by phone_no desc limit 10;
select * from user limit 10; (默认按照id正序排列取结果)
- 模糊查询
like
select phone from user where phone like '%0000%';
- 函数
1.concat函数
CONCAT函数用于将两个字符串连接起来,形成一个单一的字符串。
select concat('---','11','22','33'); ---112233
另一个更重要的作用是转换想要字段的类型,比如一个数字型DECIMAL的转换成string
select concat(amount) from table_A;
concat(REPLACE(unix_timestamp(current_timestamp(3)),'.',''))
select concat(floor(amount)),concat(date(created_at)) from table_A
MySQL中concat_ws函数 使用方法: CONCAT_WS(separator,str1,str2,...)
select concat_ws('---','11','22','33'); 11---22---33
CONCAT_WS() 代表 CONCAT With Separator ,是CONCAT()的特殊形式。第一个参数是其它参数的分隔符。分隔符的位置放在要连接的两个字符串之间。分隔符可以是一个字符串,也可以是其它参数。 注意: 如果分隔符为 NULL,则结果为 NULL。函数会忽略任何分隔符参数后的 NULL 值。
2.now()与date()
select now(); 2020-06-28 14:33:14
select Date('2019-09-08 15:00:01'); 2019-09-08
当前时间对应的Unix时间戳,单位为秒
select unix_timestamp();
SELECT concat(date(now()))
3.rand()函数
随机排序,与limit经常连用
select amount,term from table_A where amount=(select max(amount) from table_A) order by rand() limit 1;
4.md5函数
md5()函数内的参数不要加引号,否则加密出来的是特定字符加密结果,都是一样的值,而不是变量值
传参的加密:
select phone_no,md5(phone_no) from user ;
固定的加密:(只会将phone_no进行加密,而不是第一列查到的phone_no)
select phone_no,md5('phone_no') from user ;
5.length()函数
查看某个字符的长度
select length(amount) from table_A ;
6.repalce()函数
替换函数语法规则:
REPLACE(String,from_str,to_str) 即:将String中所有出现的from_str替换为to_str,经常与case when或者IF连用
展示查询替换结果,不真实替换:
select name,replace(name,'刘','六六六') as t from user_detail;
将表中的字段实际替换:
update 表名 set 字段名=replace(字段名,'原始字符','目的字符') where 条件;
update user_detail set name=replace(name,'刘','六六六') where name='XXX';
7.count()函数
查询总记录
select count(*) from user_detail where user_id between 20 and 45;
- 分支case when
select ( case when a > b then a else b end ), (case when b > c then b else c end ) from table;
eg:
select aa.c1,
case when aa.c1=1 then md5(concat(bb.phone_no,bb.id))
when aa.c1=2 then repalce(aa.c1,'**','----')
when aa.c1=3 then md5(concat(bb.phone_no))
end as phone,bb.id,bb.name
from table_AA aa,
(select c.* from table_A a ,table_B b,xyqb_user.table_C c
where a.user_id=b.id and b.id=c.u_id)bb where aa.aa.c1 in(1,2,3)
order by rand() limit 1;
- 结果去重 distinct
如果被查询的字段既有空值,又有非空值,空值也是一个特殊的结果会被DISTINCT出来
select DISTINCT(字段名) from 表名 where 条件语句;
select DISTINCT(name) from user_detail where user_id between 20 and 45;
- IF
根据一个字段的值判断
select `gender`,if(gender=1,'男','女') as '性别' from user_detail;
- group by ... having
select COUNT(*)as '>20岁人数',classid from Table1 where sex='男' group by classid,age having age>20
select COUNT(*)as '>20岁人数',classid from Table1 where sex='男' group by classid,age having max(age) ;
当同时含有where子句、group by 子句 、having子句及聚集函数时,执行顺序如下:
--执行where子句查找符合条件的数据;
--使用group by 子句对数据进行分组;对group by 子句形成的组运行聚集函数计算每一组的值;最后用having 子句去掉不符合条件的组。
注意:
1.having 子句中的每一个元素也必须出现在select列表中
2.having子句和where子句都可以用来设定限制条件以使查询结果满足一定的条件限制。
3.having子句限制的是组,而不是行。where子句中不能使用聚集函数,而having子句中可以
视图
- 定义
通俗的讲,视图就是一条SELECT语句执行后返回的结果集。 - 作用
视图是对若干张基本表的引用,一张虚表,查询语句执行的结果,不存储具体的数据(基本表数据发生了改变,视图也会跟着改变);
可以跟基本表一样,进行增删改查操作(ps:增删改操作有条件限制);
方便操作,特别是查询操作,减少复杂的SQL语句,增强可读性;
更加安全,数据库授权命令不能限定到特定行和特定列,但是通过合理创建视图,可以把权限限定到行列级别;
索引
索引是数据库中用来提高查询性能的最常用工具。
- 普通索引“ index”
- 唯一索引“unique index”
- 主键索引
主键是一种特殊的唯一索引,一般在创建表的时候指定。在 MYSQL 中,当你建立主键时,主键索引同时也已经建立起来了,不必重复设置。一个表只能有一个主键,也即只有一个主键索引 - 删除索引
DROP INDEX 索引名 ON 表名 - 使用短索引
对于CHAR和VARCHAR列,只用它的一部分来创建索引,可以节省索引空间,也会使查询更快捷。 - 根据搜索的关键字建立多列索引。
- 不要过度索引。维护索引需要成本
mysql事务
因为事务是经常需要用的知识点,给做了一个总结图,需要的可以私信
其他
- 查看一个表的建表语句
show create table funding_corp_config; - 主键和外键
主键:是唯一标识一条记录,不能有重复的,不允许为空,用来保证数据完整性
外键:是另一表的主键, 外键可以有重复的, 可以是空值,用来和其他表建立联系用的。所以说,如果谈到了外键,一定是至少涉及到两张表。 - 慢查询
sql慢查询也是经常要关注的一部分,mysql explain
参考:https://www.jianshu.com/p/ea3fc71fdc45
常见面试题:
1.你的数据库用什么存储引擎?区别是?
答案:常见的有MyISAM和InnoDB。
MyISAM:不支持外键约束。不支持事务。对数据大批量导入时,它会边插入数据边建索引,所以为了提高执行效率,应该先禁用索引,在完全导入后再开启索引。
InnoDB:支持外键约束,支持事务。对索引都是单独处理的,无需引用索引。
2.视图的作用,视图可以更改么?
视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询;不包含任何列或数据。使用视图可以简化复杂的sql操作,隐藏具体的细节,保护数据;视图创建后,可以使用与表相同的方式利用它们。
视图不能被索引,也不能有关联的触发器或默认值,如果视图本身内有order by 则对视图再次order by将被覆盖。
创建视图:create view XXX as XXXXXXXXXXXXXX;
对于某些视图比如未使用联结子查询分组聚集函数Distinct Union等,是可以对其更新的,对视图的更新将对基表进行更新;但是视图主要用于简化检索,保护数据,并不用于更新,而且大部分视图都不可以更新。
3.drop,delete与truncate的区别
drop直接删掉表 truncate删除表中数据,再插入时自增长id又从1开始 delete删除表中数据,可以加where字句。
(1) DELETE语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作。TRUNCATE TABLE 则一次性地从表中删除所有的数据并不把单独的删除操作记录记入日志保存,删除行是不能恢复的。并且在删除的过程中不会激活与表有关的删除触发器。执行速度快。
(2) 表和索引所占空间。当表被TRUNCATE 后,这个表和索引所占用的空间会恢复到初始大小,而DELETE操作不会减少表或索引所占用的空间。drop语句将表所占用的空间全释放掉。
(3) 一般效率而言,drop > truncate > delete
(4) 应用范围。TRUNCATE 只能对TABLE;DELETE可以是table和view
(5) TRUNCATE 和DELETE只删除数据,而DROP则删除整个表(结构和数据)。
(6) truncate与不带where的delete :只删除数据,而不删除表的结构(定义)drop语句将删除表的结构被依赖的约束(constrain),触发器(trigger)索引(index);依赖于该表的存储过程/函数将被保留,但其状态会变为:invalid。
(7) delete语句为DML(data maintain Language),这个操作会被放到 rollback segment中,事务提交后才生效。如果有相应的 tigger,执行的时候将被触发。
(8) truncate、drop是DLL(data define language),操作立即生效,原数据不放到 rollback segment中,不能回滚
(9) 在没有备份情况下,谨慎使用 drop 与 truncate。要删除部分数据行采用delete且注意结合where来约束影响范围。回滚段要足够大。要删除表用drop;若想保留表而将表中数据删除,如果于事务无关,用truncate即可实现。如果和事务有关,或老师想触发trigger,还是用delete。
(10) Truncate table 表名 速度快,而且效率高,因为:
truncate table 在功能上与不带 WHERE 子句的 DELETE 语句相同:二者均删除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少。DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一项。TRUNCATE TABLE 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。
(11) TRUNCATE TABLE 删除表中的所有行,但表结构及其列、约束、索引等保持不变。新行标识所用的计数值重置为该列的种子。如果想保留标识计数值,请改用 DELETE。如果要删除表定义及其数据,请使用 DROP TABLE 语句。
(12) 对于由 FOREIGN KEY 约束引用的表,不能使用 TRUNCATE TABLE,而应使用不带 WHERE 子句的 DELETE 语句。由于 TRUNCATE TABLE 不记录在日志中,所以它不能激活触发器。
- 局部性原理与磁盘预读
由于存储介质的特性,磁盘本身存取就比主存慢很多,再加上机械运动耗费,磁盘的存取速度往往是主存的几百分分之一,因此为了提高效率,要尽量减少磁盘I/O。为了达到这个目的,磁盘往往不是严格按需读取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。程序运行期间所需要的数据通常比较集中。
由于磁盘顺序读取的效率很高(不需要寻道时间,只需很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高I/O效率。
预读的长度一般为页(page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(在许多操作系统中,页得大小通常为4k),主存和磁盘以页为单位交换数据。当程序要读取的数据不在主存中时,会触发一个缺页异常,此时系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,然后异常返回,程序继续运行。
数据库优化的思路
1.SQL语句优化
1)应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
2)应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0
3)很多时候用 exists 代替 in 是一个好的选择
4)用Where子句替换HAVING 子句 因为HAVING 只会在检索出所有记录之后才对结果集进行过滤
2.索引优化
3.数据库结构优化
存储过程与触发器的区别
触发器与存储过程非常相似,触发器也是SQL语句集,两者唯一的区别是触发器不能用EXECUTE语句调用,而是在用户执行Transact-SQL语句时自动触发(激活)执行。触发器是在一个修改了指定表中的数据时执行的存储过程。通常通过创建触发器来强制实现不同表中的逻辑相关数据的引用完整性和一致性。由于用户不能绕过触发器,所以可以用它来强制实施复杂的业务规则,以确保数据的完整性。触发器不同于存储过程,触发器主要是通过事件执行触发而被执行的,而存储过程可以通过存储过程名称名字而直接调用。当对某一表进行诸如UPDATE、INSERT、DELETE这些操作时,SQLSERVER就会自动执行触发器所定义的SQL语句,从而确保对数据的处理必须符合这些SQL语句所定义的规则。