Sql必知必会

mac MySQL

下载最新的MySQL社区版
然后安装,安装过程中记住root的密码要记好
然后就是选择加密强度,不要选强加密强度,可能客户端连接不了
root对应密码3开头老八位
注意,如果没有安装Java的话,需要提前按一下,下载Java

在~/.zhsrc里面增加一行
export PATH=${PATH}:/usr/local/mysql/bin

这样就能用mysql语句了

进入mysql命令
mysql -u root -p
退出
\q

mysql
Linux 下命令操作
启动: service mysqld start
停止: service mysqld stop
重启: service mysqld restart
查看状态: service mysqld status
查看状态: systemctl status mysqld.service
/etc/init.d/mysql

sql必知必会

1、什么是sql
sql就是结构化查询语言 structured query language的缩写,是一种专门用来和数据库通信的语言。
mysql就是一种dbms(数据库管理系统),即它是一种数据库软件。
mysql工具:
mysql命令行实用程序
mysql administrator mysql管理器是一个图形交互客户机,用来简化mysql服务器的管理。
mysql query browser是一种图形交互客户机,用来编写和执行mysql命令。

数据库连接
选择数据库
use xxxdatabase;
如果你不知道有哪些表,可以用show databases;来显示所有的数据库。
同理,show tables;显示该数据库下的所有表。
同理,show columns from customers;显示数据库的各列的情况。也可以用describe customers;来显示各列的类型和定义。
此外还有show grants显示授予用户的安全权限。
show errors好show warnnings显示服务器错误或者警告信息。

第四章 检索数据

一般,除非你确实需要表中的每个列,否则最好别使用通配符*,虽然通配符可能使你自己省事,不用明确列出所需列,但检索不需要的列通常会降低检索和应用程序的性能。

检索不同行,如果返回结果是有重复的,如何去重?
select vend_id from mysql_learn.products group by vend_id;
select distinct vend_id from mysql_learn.products;
两种办法都能实现

不能部分使用distinct,distinct关键字应用于所有列而不是前置它的列,如果给出select distinct vend_id,prod_price,除非指定的两个列都不同,否则所有行都将被检索出来。

限制结果limit
limit n后面跟一个数字,表示返回不多于n行。
limit m,n后面跟两个数字,表示从行m开始,输出n行
记住,mysql是从行0开始,当行数不够时,输出实际行数。
为了方便limit m,n理解,mysql5之后,可以支持limit n offset m表示。

第五章 排序检索数据

按多个列排序
select prod_id,prod_price,prod_name from products order by prod_price,prod_name;
对多个列排序时,仅在多个行具有相同的prod_price时才对产品按prod_name排序,如果prod_price所有数据是唯一的,则不会对prod_name排序。

排序方向,默认的asc(ascending)升序,,可以不明确写出来,降序是desc(descending)。

select prod_id,prod_price,prod_name from products order by prod_price desc,prod_name;
desc关键字只应用到直接位于起前面的列名,所以会对prod_price进行降序排列,如果prod_price一样时,会对prod_name进行升序排列。

order by和limit组合,通常可以拿到最高或者最低的数。
select prod_price from products order by prod_price desc limit 1;

第六章 过滤数据

order by和where同时使用时,必须使order by在where的后面,否则会报错。
where子句操作符

操作符 说明
= 等于
<> 不等于
!= 不等于
< 小于
<= 小于等于
> 大于
>= 大于等于
BETWEEN 在指定的两个值之间

where prod_name='fuses'说明,由于mysql执行匹配时,默认不区分大小写,所以fuses和Fuses都会被选中。

单引号用来限定字符串

select prod_name,prod_price from products where prod_price between 5 and 10;
在使用between时,必须指定最低值和最高值,而且中间必须用and连接。则匹配范围就限定在最低值和最高值中间,包括最低值和最高值。

空值检查
NULL 无值(no value),它与字段包含0、空字符串或者仅有空格不同。

select cust_id from customers where cust_email IS NULL;

第七章 数据过滤

组合where子句
组合where子句可以用and或者or
and表示筛选满足所有where子句的数据
or表示筛选满足其中任意一个where子句的数据

计算次序
这里where子句可包含任意多个and和or,这里就出现了一个有意思的问题,优先级问题。
默认情况下,and优先级比or优先级高。

select prod_name,prod_price from products where vend_id=1002 or
vend_id=1003 and prod_price >=10;
这个语句的意思是筛选vend_id=1002的所有数据和vend_id=1003且prod_price >=10的数据。

所以,如果你想选择 vend_id = 1002 和1003 并且prod_price >=10的所有数据,应该加上括号
select prod_name,prod_price from products where (vend_id=1002 or
vend_id=1003) and prod_price >=10;

上面的括号 都是等于,其实可以用in操作符
select prod_name,prod_price from products where vend_id in(1002,1003) and prod_price >=10;

not操作符
select prod_name,prod_price from products where vend_id not in(1002,1003) and prod_price >=10;

第八章 用通配符进行过滤

百分号(%)通配符
%表示任何字符出现任意次数包括0次
select * from products where prod_name like '%anvil%';
下划线(_)通配符
_通配符只匹配一个字符

使用通配符技巧
1、不要过度使用通配符。
2、在确实需要使用通配符时,除非绝对有必要,否则不要把他们用在搜索模式的开始处。这样是最慢的。

第九章 用正则表达式进行搜索

基本字符匹配
select * from products where prod_name regexp '1000' order by prod_name;
匹配prod_name包含文本1000所有行。

select * from products where prod_name like '1000' order by prod_name;
这样执行,不会返回数据,因为like是匹配整列数据,除非使用通配符。而regexp是列值内进行匹配,也就是匹配子串,匹配到了就返回。

select * from products where prod_name regexp '.000' order by prod_name;
.在正则表达式里面表示匹配任意一个字符,因此,1000和2000都匹配

如果匹配想区分大小写,可以使用binary关键字。如where prod_name regexp binary 'JetPack .000';

or匹配
select * from products where prod_name regexp '1000|2000' order by prod_name;

匹配资金字符之一
select * from products where prod_name regexp '[123] Ton' order by prod_name;
表示匹配 1 Ton,2 Ton,3 Ton其中一个就行
[]是另一种形式的or
select * from products where prod_name regexp '[1|2|3] Ton' order by prod_name;

如果写成这样
select * from products where prod_name regexp '1|2|3 Ton' order by prod_name;
则变成了意思是匹配1或者2或者3 Ton,完全不是原来的意思了,注意。

匹配范围
[0123456789] 可以简化成[0-9],类似的有[a-z]

匹配特殊字符
为了匹配特殊字符,需要在前面加上\,比如为了匹配-,需要写成\-,这就是所谓的转义。

匹配多个实例

元字符 说明
* 0个或者多个匹配
+ 1个或者多个匹配相当于{1,}
? 0个或者1个匹配
{n} 指定数目的匹配
{n,} 不少于指定数目的匹配
{n,m} 匹配数目范围

select * from products where prod_name regexp '\([0-9] sticks?\)' order by prod_name;

select * from products where prod_name regexp '[[:digit:]]{4}' order by prod_name;
表示匹配连在一起的4个数字

定位符

元字符 说明
^ 文本的开始
$ 文本的结束
[[:<:]] 词的开始
[[:>:]] 词的结束

^的双重用途
在集合中[],用它来否定集合,否则表示字符串的开始。

第十一章 创建计算字段

1、拼接字段
vendors表包含供应商名和位置信息,假如要生成一个表,需要用name(location)形式列出供应商名称和位置。
拼接(concatenate)将值联结到一起构成单个值。
select concat(vend_name,'(',vend_country,')') from vendors order by vend_name;
可以通过rtrim()函数去掉值右边所有的空格进行格式整理
select concat(rtrim(vend_name),'(',rtrim(vend_country),')') from vendors order by vend_name;

使用别名
select concat(rtrim(vend_name),'(',rtrim(vend_country),')') as vend_title from vendors order by vend_name;
使用别名的好处是,别的地方可以引用他。

执行算数计算
select prod_id,quantity,item_price quantity*item_price as expanded_price from orderitems where order_num=20005;

操作符 说明
+
-
*
/

第十二章 使用数据处理函数

文本处理函数
使用rtrim()去除空格,使用upper()将文本转成大写。

函数 说明
left() 返回字符串左边的字符
length() 返回串的长度
locate() 找出串的一个子串
lower() 换成小写
ltrim() 去掉串左边的空格
right() 返回字符串右边的字符
rtrim() 去掉串右边的空格
soundex() 返回串的soundex值
substring() 返回子串的字符
upper() 换成大写

日期和时间处理函数

函数 说明
adddate() 增加一个日期(天、周等)
addtime() 增加一个时间(时、分等)
curdate() 返回当前日期
curtime() 返回当前时间
date() 返回日期时间的日期部分
datediff() 计算两个日期之差
day() 计算一个日期的天数部分
dayofweek() 对应日期返回星期几
hour() 返回一个时间的小时部分
minute() 返回一个时间的分钟部分
second() 返回一个时间的秒数部分
month() 返回一个日期的月份部分
now() 返回当前日期和时间
time() 返回一股日期时间的时间部分
year() 返回一个日期的年份部分

select * from orders where date(order_date) between '2005-09-01' and '2005-09-30';

第十二章 汇总数据

聚集函数

函数 说明
avg() 返回某列的平均值
count() 返回某列的函数
max() 返回某列的最大值
min() 返回某列的最小值
sum() 返回某列值之和

count(*)对表中行的数目进行计数,不管表列中包含的是空值(null)还是非空值。
count(column)对特定列中具有值的行进行计数,忽略null值。

聚集不同值
如前面提到,所有的聚集函数都是对筛选的所有行进行计算,默认是all参数或者不给参数。
如果只对不同值进行聚集,指定distinct参数。
select avg(distinct prod_price) as avg_price from products where vend_id=1003;
这里只会把1003不同价格的平均值取出来,把相同价格的行会过滤。

第十三章 分组数据

创建分组
select vend_id,count(*) as num_prods from products group by vend_id;
group by在where之后,在order by之前。

过滤分组
having用法非常类似where,唯一的差别是where过滤行,having过滤分组。
select vend_id,count() as num_prods from products group by vend_id having count()>=2;

group by是分组,order by是按照列排序,两者略不同。

第十四章 使用子查询

利用子查询进行过滤
检索所有包含物品tnt2的所有订单的编号
检索具有前一步骤列出的订单编号的所有客户的id

select order_num from orderitems where prod_id = 'TNT2';
得出order_num是20005和20007

在下一步查询中
select cust_id from orders where order_num in (20005,20007);
select cust_id from orders where order_num in (select order_num from orderitems where prod_id = 'TNT2');
在select语句中,子查询总是从内向外处理。所以是先查询括号内的select语句,然后执行括号外面的select语句。

在where子句中使用子查询,应该保证select语句具有与where子句相同数目的列。

作为计算字段使用子查询
从customers表中检索客户列表
对于检索出的每个客户,统计其在orders表中的订单数目

要检索订单数目,可以使用count()进行计数,并且通过一条where子句来过滤某个特定的客户id
select count(
) as orders from orders where cust_id=10001;
对于某个客户执行count()计数,应该将count()作为一个子查询。

select cust_name,cust_state,(select count(*) from orders where orders.cust_id=customers.cust_id) as orders from customers order by cust_name;

第十五章 联结表

设计表时,为了不让数据重复,会解耦创建不同的表,比如vendors表包含所有供应商信息,每个供应商占一行,products表只存储产品信息,它除了存储供应商id之外,不存储其他供应商信息。vendors表的主键又叫products表的外键。

创建联结
select vend_name,prod_name,prod_price from vendors,products where vendors.vend_id=products.vend_id order by vend_name,prod_name;

联结中,where子句的重要性
在数据库表中不存在能只是mysql如何对表进行联结的东西,必须在sql语句中明确除了。在联结两个表时,你实际上做的就是将第一个表中的每一行和第二个表中的每一行配对。where子句作为过滤条件。它只包含那些匹配给定条件的行。没有where子句,第一个表中的每个行将与第二个表中的每一行配对,而不管逻辑上是否可以配在一起。

前面提到的联结称为等值联结。它基于两个表之间的相等测试。这种联结也称为内部联结。
select vend_name,prod_name,prod_price from vendors inner join products on vendors.vend_id=products.vend_id;
这个语句与前面的语句效果一样。on后面的条件与where一样。

联结多个表
select cust_name,cust_contact from customers,order,orderitems where customers.cust_id=orders.cust_id and orderitems.order_num=orders.order_num and prod_id='TNT2';

第十六章 创建高级联结

表别名 自联结
假如发现id为DTNTR的物品存在问题,因此想知道生产该物品的供应商的其他产品也是否存在这些问题。
select prod_id,prod_name from products where vend_id = (select vend_id from products where prod_id='DTNTR');

select p1.prod_id,p1.prod_name from products as p1,products as p2 where p1.vend_id=p2.vend_id and p2.prod_id='DTNTR';

检索所有客户及其订单
select customers.cust_id,orders.order_num from customers inner join orders on customers.cust_id=orders.cust_id;
外部联结语法类似,为了检索所有客户,包括哪些没有订单的客户,可进行如下改造:
select customers.cust_id,orders.order_num from customers left outer join orders on customers.cust_id=orders.cust_id;

outer join使用时,必须使用right或者left关键字,指明其包括所有行的表

第十七章 组合查询

假如查询价格小于等于5的所有物品,并且包括供应商1001和1002生产的所有物品。
1、where查询
select vend_id,prod_id,prod_price from products where prod_price<=5 or vend_id in (1001,1002);
2、union-组合查询
首先筛选小于等于5的物品
select vend_id,prod_id,prod_price from products where prod_price<=5;
然后筛选供应商1001,1002的物品
select vend_id,prod_id,prod_price from products where vend_id in (1001,1002);
两个组合起来
select vend_id,prod_id,prod_price from products where prod_price<=5 union select vend_id,prod_id,prod_price from products where vend_id in (1001,1002);
union默认会去重,如果你不想去重,那就使用union all显示所有两次查询的结果。
注意,union语句中,order by只用在最后出现,并且两个筛选结果同样都会有order by效果。

第十八章 文本搜索

要想启用全文本搜索,create table语句接受fulltext子句。

create table products
(
note_id int not null auto_increment,
note_text text null,
primary key(note_id),
fulltext(note_text)
)engine=myisam;

进行全文本搜索
select note_text from productnotes where match(note_text) against('rabbit');
意思是搜索note_text列,搜索含有rabbit的文本
match后面跟列,against后面跟匹配的词。
可以用where实现
select note_text from productnotes where note_text like '%rabbit%';

使用查询扩展
select note_text from productnotes where match(note_text) against('rabbit' with query expansion);
查询扩展会把rabbit相关的查询也会显示出来。

布尔文搜索
select note_text from productnotes where match(note_text) against('+rabbit +bait' in boolean mode);
搜索包含rabbit和bait的行。

布尔操作符 说明
+ 包含,词必须存在
- 排除,词必须不出现
> 包含,而且增加等级值
< 包含,且减少等级值
() 把词组成子表达式,允许这些子表达式作为一个组被包含、排除排列等
~ 取消一个词的排序值
* 词尾的通配符
"" 定义一个短语,余单个词的列表不一样,它匹配整个短语以便包含或排除这个短语

第十九章 插入数据

insert into customers values('pep e. lapew','100 main street','los angeles','ca','90046','usa',null,null);
insert into customers(cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country,cust_contact,cust_email) values('pep e. lapew','100 main street','los angeles','ca','90046','usa',null,null);
虽然前面两种都能正确插入数据,但是第一种不推荐,因为values后面的值是必须和数据库里面的表一一对应的,第二种方式,显然更靠谱,因为它指定了顺序,就算后面数据库表结构有变动,那这里也是可以正常插入的。
如果表的定义允许,则可以在insert操作中省略某些列,不过省略的列必须满足以下某个条件:
1、该列定义为允许null值(无值或空值)
2、在表定义中给出默认值。这表示如果不给出值,将使用默认值。

插入多行数据
insert into customers(cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country,cust_contact,cust_email) values('pep e. lapew','100 main street','los angeles','ca','90046','usa'),('m. martian','42 galaxy way','new york','ny','11213','usa');

插入检索出的数据
顾名思义,就是insert的值来源于select的值。
insert into customers(cust_id,cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country) select cust_id,cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country from custnew;
这个例子从custnew中将所有数据导入customers.

第二十章 更新和删除数据

update customers set cust_name='the fudds',cust_email='[email protected]' where cust_id=10005;
ignore关键字,如果用update语句更新多行,并且在更新这些行中的一行或者多行出现一个错误,则整个update操作被取消。可使用ignore关键字,使得update继续。update ignore customers...

删除数据
delete from customers where cust_id=10006;
如果想删除整个表,不能使用delete,要用truncate table语句。

第二十一章 创建和操作表

创建表
create table customers
(
cust_id int not null auto_increment,
cust_name char(50) not null,
cust_address char(50) null,
cust_city char(50) null,
cust_state char(5) null,
cust_zip char(10) null,
cust_country char(50) null default 'usa',
cust_contact char(50) null,
cust_email char(255) null,
primary key(cust_id)
)engine=innodb;

更新表
alter table vendors add vend_phone char(20);
alter table vendors drop column vend_phone;

删除表
drop table customes;

重命名表
rename table customers2 to customers, back_vendors to vendors;

第二十二章 使用视图

视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询。

select cust_name,cust_contact from customers,orders,orderitems where customers.cust_id=orders.cust_id and orderitems.order_num=orders.order_num and prod_id='tnt2';
此查询用例检索订购了某个特定产品的客户。任何需要这个数据的人都必须理解相关表结构,并且知道如何创建查询和对表进行联结。为了搜索其他产品的相同数据,必须修改最后的where子句。
现在,假如可以把整个查询包装成一个名为productcustomers的虚拟表,则可以轻松的检索相同的数据:
select cust_name,cust_contact from productcustomers where prod_id='tnt2';
这就是视图的作用。productcustomers是一个视图,作为视图,它不包含表中应该有的如何列或数据,它包含的是一个sql查询。

为什么使用视图
1、重用sql语句
2、简化复杂的sql操作。在编写查询后,可以方便的重用它而不必知道他的基本查询细节
3、使用表的组成部分而不是整个表
4、保护数据,可以给用户授予表的特定部分的访问权限而不是整个表的访问权限
5、更改数据格式和表示,视图可返回与底层表的表示和格式不同的数据。

在视图创建之后,可以用与表基本相同的方式利用他们。

最主要的点:视图仅仅是用来查看存储在别处的数据的一种设施。视图本身不包含数据。它的数据是从其他表检索出来的。在添加或更改表中的数据时,视图将返回改变过的数据。

因为视图使用时,都必须处理查询执行时所需的任一检索。如果用了多个联结和过滤创建了复杂的视图或者嵌套了视图,可能会发现性能下降厉害,因此,在部署大量视图应用前,应该进行测试。

视图规则和限制
1、与表一样,视图必须命名唯一
2、order by可以用在视图中,但如果从该视图检索数据的select语句中也有order by,那么该视图的order by将被覆盖
3、视图不能索引,也不能有关联的触发器活默认值。
4、视图可以和表一起使用。

create view productcustomers as select cust_name,cust_contact,prod_id from customers,orders,orderitems where customers.cust_id=orders.cust_id and orderitems.order_num=orders.order_num;
这条语句创建一个名为productcustomers的视图,它联结三个表,以返回已订购了任意产品的所有客户的列表。

为检索订购了'tnt2'的客户,可进行如下检索:
select cust_name,cust_contact from productcustomers where prod_id='tnt2';

select contact(rtrim(vend_name),'(',rtrim(vend_country),')') as vend_title from vendors order by vend_name;
如果经常用到这个联结,则可以写成一个视图
create view vendorlocations as select contact(rtrim(vend_name),'(',rtrim(vend_country),')') as vend_title from vendors order by vend_name;

如果需要用到联结,则只需要执行
select * from vendorlocations;

第二十三章 使用存储过程

创建存储过程
create procedure productpricing()
begin
select avg(prod_price) as priceaverage from products;
end;

执行存储过程
call productpricing();

删除存储过程
drop procedure productpricing;

create procedure productpricing(
out pl decimal(8,2),
out ph decimal(8,2),
out pa decimal(8,2)
)
begin
select min(prod_price) into pl from products;
select max(prod_price) into ph from products;
select avg(prod_price) into pa from products;
end;

call productpricing(@pricelow,@pricehigh,@priceaverage);
mysql变量都必须以@开头。

select @priceaverage;

create procedure ordertotal(
in onumber int,
out ototal decimal(8,2)
)
begin
select sum(item_price*quantity) from orderitems where order_num=onumber into ototal;
end;

call ordertotal(20005,@total);

select @total;

第二十四章 使用游标

游标(cursor)是一个存储在mysql服务器上的数据库查询,它不是一个select语句,而是被该语句检索出来的结果集。
1、在能够使用游标前,必须声明它。这个过程实际上没有检索数据。它只是定义要使用的select的语句。
2、一旦声明后,必须打开游标以供使用。这个过程用前面定义的select语句把数据实际检索出来。
3、在结束游标使用时,必须关闭游标。

mysql游标只能用于存储过程和函数。

create procedure processorders()
begin
declare ordernumbers cursor
for
select order_num from orders;
end;

打开游标
open ordernumbers;
在处理open动作时,存储检索出的数据以供浏览和滚动。

关闭游标
close ordernumbers;

第二十五章 使用触发器

create trigger newproduct after insert on products for each row select 'product added';
操作发生在insert之后,这个触发器还指定for each row,因此代码对每个插入行执行。文本'product added'将对每个插入的行显示一次。

只有表才支持触发器,视图和临时表都不支持。

每个表最多支持6个触发器,insert update delete的前和后。

删除触发器
drop trigger newproduct;

在update触发器中,可以引用一个old的虚拟表访问update更新前的值,引用一个new的虚拟表访问新更新的值。

下面例子保证州缩写总是大写。
create trigger updateevendor before update on vendors for each row set new.vend_state=upper(new.vend_state);

set是设置值,select是显示。

第二十六章 管理事务

哪些语句可以回退
insert update delete可以回退,但是不能回退create,drop

transaction 事务,指一组sql语句
rollback 回退,指撤销指定sql语句的过程
commit 提交,指将未存储的sql语句写入数据库
savepoint 保留点 指事务处理中设置的临时站位符,你可以对它发布回退。

select * from ordertotals;
start transaction;
delete from ordertotals;
select * from ordertotals;
rollback;
select * from ordertotals;

rollback会回退transaction之后到rollback的语句。
事务中,不会存在隐性提交,即implicit commit,我们普通的sql语句一般都是隐性提交。
事务中,必须用commit指定提交。
start transaction;
delete from ordertimes where order_num=20010;
delete from orders where order_num=20010;
commit;

savepoint delete1;
rollback to delete1;

你可能感兴趣的:(Sql必知必会)