目录
创建新表
1.子查询
连接表格,在WHERE 子句或 HAVING 子句中插入另一个 SQL 语句
子查询语句分为两种内查询,外查询
内查询语句作为外查询语句的查询结果
SELECT SUM(Sales) FROM Store_Info WHERE Store_Name IN #外查询
#以内查询的Store_Name最为查询列表,显示Sales字段的总和
(SELECT Store_Name FROM location WHERE Region = 'West'); #内查询
#查询location表中,字段Region的值为West的Store_Name字段的信息
1.1 EXISTS
用来判断内查询的结果是否存在,若存在则执行外查询,若不存在不会执行
1.2 三种连接方式
1.2.1 inner join(内连接)
只返回两个表中联结字段相等的行
SELECT * FROM location A INNER JOIN store_info B on A.Store_Name = B.Store_Name ;
#将location表和store_info分别赋予别名A和B 将A表和B表进行内连接,连接条件为Store_name字段内容相同
1.2.2 left join (左连接)
返回包括左表中的所有记录和右表中联结字段相等的记录
SELECT * FROM location A, store_info B WHERE A.Store_Name = B.Store_Name;
1.2.3 right join (右连接)
返回包括右表中的所有记录和左表中联结字段相等的记录
2.VIEW
可以被当作是虚拟表或存储查询。当我们需要进行连接查询时,需要输入冗长的代码,而且查询的结果无法保存,但是如果我们使用视图保存连接查询的结果,就可以快速查阅。视图跟表格的不同是,表格中有实际储存数据记录,而视图是建立在表格之上的一个架构,它本身并不实际储存数据记录。
CREATE VIEW "视图表名" AS "SELECT 语句";
#创建视图
SELECT * FROM 视图名;
#查看视图
DROP 视图名;
#删除视图
例如我将上面的右连接创建为视图
创建视图的几种限制
视图表能否修改取决于,视图表和原表的结构是否一致。
要对某些列取别名,并保证列名的唯一
定义视图的查询语句中不能够使用某些关键字如:order by
3.UNION
联集,将两个SQL语句的结果合并起来,两个SQL语句所产生的字段需要是同样的数据记录种类生成结果的数据记录值将没有重复,且按照字段的顺序进行排序
[SELECT 语句 1] UNION [SELECT 语句 2];
UNION ALL :将生成结果的数据记录值都列出来,无论有无重复
[SELECT 语句 1] UNION ALL [SELECT 语句 2];
3.1 取两个SQL语句结果交集的几种办法
SELECT A.Store_Name FROM location A INNER JOIN Store_Info B ON A.Store_Name = B.Store_Name;
SELECT A.Store_Name FROM location A INNER JOIN Store_Info B USING(Store_Name);
#取两个SQL语句结果的交集,且没有重复
SELECT DISTINCT A.Store_Name FROM location A INNER JOIN Store_Info B USING(Store_Name);
SELECT DISTINCT Store_Name FROM location WHERE (Store_Name) IN (SELECT Store_Name FROM Store_Info);
SELECT DISTINCT A.Store_Name FROM location A LEFT JOIN Store_Info B USING(Store_Name) WHERE B.Store_Name IS NOT NULL;
SELECT A.Store_Name FROM (SELECT B.Store_Name FROM location B INNER JOIN Store_Info C ON B.Store_Name = C.Store_Name) A
GROUP BY A.Store_Name;
SELECT A.Store_Name FROM
(SELECT DISTINCT Store_Name FROM location UNION ALL SELECT DISTINCT Store_Name FROM Store_Info) A
GROUP BY A.Store_Name HAVING COUNT(*) > 1;
3.2 无交集值的几个办法
显示第一个SQL语句的结果,且与第二个SQL语句没有交集的结果,且没有重复
SELECT DISTINCT Store_Name FROM location WHERE (Store_Name) NOT IN (SELECT Store_Name FROM Store_Info);
SELECT DISTINCT A.Store_Name FROM location A LEFT JOIN Store_Info B USING(Store_Name) WHERE B.Store_Name IS NULL;
SELECT A.Store_Name FROM
(SELECT DISTINCT Store_Name FROM location UNION ALL SELECT DISTINCT Store_Name FROM Store_Info) A
GROUP BY A.Store_Name HAVING COUNT(*) = 1;
4. CASE
是 SQL 用来做为 IF-THEN-ELSE 之类逻辑的关键字
SELECT CASE ("字段名")
WHEN "条件1" THEN "结果1"
WHEN "条件2" THEN "结果2"
...
[ELSE "结果N"]
END
FROM "表名";
条件可以是值也可以是公式。
5. 空值和无值
1.无值的长度为 0,不占用空间的;而 NULL 值的长度是 NULL,是占用空间的。
2.IS NULL 或者 IS NOT NULL,是用来判断字段是不是为 NULL 或者不是 NULL,不能查出是不是无值的。
3.无值的判断使用=''或者<>''来处理。<> 代表不等于。
4.在通过 count()指定字段统计有多少行数时,如果遇到 NULL 值会自动忽略掉,遇到无值会加入到记录中进行计算。
6.正则表达式
^ 匹配文本的开始字符 ‘^bd’ 匹配以 bd 开头的字符串
$ 匹配文本的结束字符 ‘qn$’ 匹配以 qn 结尾的字符串
. 匹配任何单个字符 ‘s.t’ 匹配任何 s 和 t 之间有一个字符的字符串
* 匹配零个或多个在它前面的字符 ‘fo*t’ 匹配 t 前面有任意个 o
+ 匹配前面的字符 1 次或多次 ‘hom+’ 匹配以 ho 开头,后面至少一个m 的字符串
字符串 匹配包含指定的字符串 ‘clo’ 匹配含有 clo 的字符串
p1|p2 匹配 p1 或 p2 ‘bg|fg’ 匹配 bg 或者 fg
[...] 匹配字符集合中的任意一个字符 ‘[abc]’ 匹配 a 或者 b 或者 c
[^...] 匹配不在括号中的任何字符 ‘[^ab]’ 匹配不包含 a 或者 b 的字符串
{n} 匹配前面的字符串 n 次 ‘g{2}’ 匹配含有 2 个 g 的字符串
{n,m} 匹配前面的字符串至少 n 次,至多m 次 ‘f{1,3}’ 匹配 f 最少 1 次,最多 3 次
7.存储过程
存储过程是一组为了完成特定功能的SQL语句集合。
存储过程是一组可编程的函数,是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。
存储过程的优点
- 直接在数据库层运行,从而减少网络带宽的占用和减少查询任务执行的延迟。提高了代码的复用性和可维护性,可以聚合业务规则,加强一致性并提高安全性。
- 可以带来安全性优势以及优雅的权限控制手段。一个典型的例子就是银行中的转账存储过程。存储过程在一个事务里完成转账及记录用于后续审核的完整操作日志。可以通过存储过程完成访问而无需对涉及到的表进行提权。
- 服务端会缓存存储过程的执行,这样可以减少重复执行的负荷。
- 存储过程存储在服务端,因此对于服务单的部署、备份和维护而言,存储过程更好维护
- 可以将应用开发者与数据库开发者的工作分离,因此可以让数据库牛人来写存储过程,而避免某些应用开发者编写SQL水平不高的问题。
7.1 创建存储过程
实现过程:
DELIMITER !! #将语句的结束符号从分号;临时修改,以防出问题,可以自定义
CREATE PROCEDURE XXX() #创建存储过程,过程名自定义,()可带参数
BEGIN #过程体以关键字BEGIN开始
select * from xxx; #过程体语句
END!! #过程体以关键字END结尾
DELIMITER ; #将语句的结束符号恢复为分号
call XXX; #调用存储过程
查看存储过程
show create procedure [数据库.]储存过程名; #查看某个储存过程的具体信息
show create procedure XXX;
show procedure status [like '%XXX%'] \G
7.2 查看存储过程
#查看某个存储过程的具体信息(如果在指定库中,库名可以省略)
SHOW CREATE PROCEDURE [数据库.] 存储过程名;
7.3 删除存储过程
#语法
DROP PROCEDURE IF EXISTS 过程名;
7.4 过程控制
条件语句if-then-else ···· end if
delimiter $$ #修改默认结束符为$$
create procedure proc12(in pro int) #创建存储过程proc2,参数为pro,类型为int
-> begin #过程体以关键字begin开始
-> declare var int; #定义变量var为int类型
-> set var=pro*3; #设置变量var等于传入参数的3倍
-> if var>=10 then #如果变量var大于10,则执行下面过程体
-> update students set age=age+10; #设置表students中的age加10
-> else #如果变量var不大于10,则执行下面过程体
-> update students set age=age-10; #设置表students中的age减10
-> end if; #结束if语句
-> end $$ #创建存储过程结束
delimiter ; #重新修改默认结束符为原始的;
循环语句while ···· end while
DELIMITER .. #修改默认结束符为..
-> create procedure t3() #创建存储过程t2
-> begin #过程体以关键字begin开始
-> declare i int; #定义变量i为int类型(长度最大为10)
-> set i = 1; #设置i = 1;
-> while i <= 3 #使用while循环,i要小于3
-> do select * from info; #满足条件则进行添加数据,内容为变量i
-> set i=i+1; #变量i每次循环后加1
-> end while; #结束while循环
-> end .. #创建存储过程结束
delimiter ; #重新修改默认结束符为原始的;
8. 批量修改时间字段的方法
这是我的主表,可以看到date是用来存储时间的字段。一般来说,我们修改信息可以使用update来进行单行数据的更新,但是如果我们需要同时修改一整列的时间数据,工作量是无法想象的。
update 表名 set 时间字段=date_add(时间字段,interval+加减的天数 day);
update 表名 set 时间字段=date_add(时间字段,interval+加减的月数 month);
update 表名 set 时间字段=date_add(时间字段,interval+加减的年数 year);
这个命令可以帮助我解决这个问题