您的位置:首页 > 数据库 > MySQL

MySql超级详细基础教程

2017-12-06 22:19 316 查看
mysql.exe 客户端

mysql -h localhost -uroot -p

连接到mysqld.exe

数据库->表(行,列)

表(多行多列的)

insert(增)

可以插入所有列,也可以插入些列。

列与值严格对应

数字与字符串要注意,数字不必加单引号,但是字符串必须加单引号

insert into userdata (phone,email,nickname) values ('13333608985','kkcode@126.com','kkcode');


delete(删)

删除必是一行

delete from 表名

where expr;

delete from userdata
where id = 3;


update(改)

改哪张表?

改哪几列的值?

分别改为什么值?

在那些行生效?

update 表名 set

列1 = 新值1,

列2 = 新值2

where expr

update 需加where条件,不然影响所有行,很危险

update userdata set
password='123456'
where phone='13333608985';


select(查)

查询哪几列?从那张表查?要选哪几行?

select 列1,列2,…列n from 表名

where expr

理解查询模型

select name,age from user where uid=2;(投影运算)

列就是变量(变量可以参与运算),where是个表达式,为真则取出。
来到第一行,表达式为假不要,
来到第二行,表达式为真取出来。

select goods_id,goods_name,market_price-shop_price
from goods;(广义投影,列之间做运算)


逻辑运算符

大于等于小于,小于等于,大于等于,基本与php一样

逻辑与或非(&&或and,||或or,!或NOT)

在某个区间内(between),

在某个集合内(in)

不等于(!=或<>)

in(在某集合内)

select goods_id,goods_name,cat_id from goods where
cat_id in (4,11);

// 取出不属于第三栏目且不属于第11栏目的商品
select goods_name,cat_id from goods
where
cat_id not in(3,11);


between(在某个区间内)

select goods_id,goods_name,shop_price from goods where
shop_price>=100&&shop_price<=500

等价于
select goods_id,goods_name,shop_price from goods where
shop_price between 100 and 500;


运算符优先级

and 大于 or

// 取出第三个栏目下面价格<1000或3000,且点击量大于5的

//错误
-> select goods_name,cat_id,shop_price,click_count from goods
where
(cat_id=3)
and
(shop_price <1000) or (shop_price>3000)
and click_count>5;

// 正确
-> select goods_name,cat_id,shop_price,click_count from goods
where
(cat_id=3)
and
(shop_price <1000 or shop_price>3000)
and click_count>5;


模糊查询

取出诺基亚系列的手机

like模糊匹配

% 通配任意字符

_ 通配单一字符

// 查出以"诺基亚"开头的手机
-> select goods_id,goods_name
from goods
where
goods_name like "诺基亚%";

//查出"诺基亚nXX"系列的手机
-> select goods_id,goods_name
from goods
where
goods_name like "诺基亚n__";


奇怪的NULL

// 错误
select * from tmp where name = null;

// 正确,使用谓词 is
select * from tmp where name is null;

// 正确,使用谓词 is
select * from tmp where name is not null;

一般建表时,不允许插入null


五种子句

where

group by分组与统计函数

select cat_id,avg(shop_price) from goods
group by cat_id;


统计函数

max()求最大

count()求行数

avg() 求平均

min()求最小

sum()求总和

having筛选结果集

// 查询出比市场价优惠200块钱以上的商品,普通sql
select goods_id,goods_name,market_price-shop_price from goods
where market_price-shop_price>200;

// 赋值给一个变量,该SQL语句错误(说没有youhui_price这一列)
select goods_id,goods_name,market_price-shop_price as youhui_price from goods
where youhui_price>200; //报错原因:where是针对磁盘的数据文件

// 引入having
select goods_id,goods_name,market_price-shop_price as youhui_price from goods
where 1 having youhui_price>200; //报错原因:where是针对磁盘的数据文件


order by排序

// 升序(默认)
select goods_id,shop_price from goods order by shop_price asc;

// 降序
select goods_id,shop_price from goods order by shop_price desc;

// 多次排序
select goods_id,cat_id,shop_price from goods order by cat_id asc,shop_price desc;


limit(offset,rows)

select goods_id,shop_price from goods order by shop_price asc limit 0,3;

子句的查询陷阱

查询每个栏目下最新的商品(goods_id最大为最新)

where 型子查询

内层查询的结果,作为外层sql的比较条件

// 查询最新的商品(goods_id最大为最新)
select goods_id,goods_name from goods order by goods_id desc limit 1;

// 查询出最大的goods_id
select max(goods_id) from goods;

select goods_id,goods_name from goods where goods_id=(select max(goods_id) from goods);

// 解决子句查询陷阱的问题
select max(goods_id) from goods group by cat_id;
select goods_id,goods_name from goods where goods_id in(select max(goods_id) from goods group by cat_id);


from 型子查询

查询的结果集,起一个别名作为一个临时表

// 解决子句查询陷阱的问题
select goods_id,cat_id,goods_name from (SELECT * FROM `goods` WHERE 1 group by cat_id asc,goods_id desc) as temp group by cat_id;


exists 型子查询

查询出有商品的栏目

select * from category where exists (select * from goods where goods.cat_id=category.cat_id);

新手1+N模式查询

查询价格大于3000元的商品及其栏目名称

// 新手
$sql = select goods_id,goods_name,shop_price from goods where shop_price>2000;
$rs = mysql_query($sql);
$data = array();
while(){
$row...
}

$data = array(7条商品);

foreach($data as $goods){
$sql = select cat_name from category where cat_id = $goods['cat_id'];
}

1条查询数据=>得到N待查数据=》引发N条查询

// 老手
使用一条sql语句解决此问题(连接查询)


内连接查询

select xxx from table1 inner join table2 on table1.xx=table2.xx;

truncate boy;//清楚boy表的所有数据

// 内连接查询
select boy.hid,bname,girl.hid,gname from boy inner join girl
on boy.hid = girl.hid;


左连接和右连接

左连接以左表数据为准,查询右表相关数据,查不到补NULL

// 左连接查询
select boy.hid,bname,girl.hid,gname from boy left join girl
on boy.hid = girl.hid;

// 右连接查询
select boy.hid,bname,girl.hid,gname from boy right join girl
on boy.hid = girl.hid;

// 练习
// 第一步,先使用内连接得到主队的队名
select m.*,t.tname
from
m inner join t on m.hid=t.tid;

// 第二步,再次使用内连接得到客队的队名
select m.*,t1.tname,t2.tname
from
m inner join t as t1 on m.hid=t1.tid inner join t as t2 on m.gid=t2.tid;

// 第三步,确定比赛时间
select mid,t1.tname as htame,mres,t2.tname as gtame,matime
from
m inner join t as t1 on m.hid=t1.tid inner join t as t2 on m.gid=t2.tid
where matime between '2006-06-01' and '2006-07-01';


union查询

union查询就是把2条或多条sql查询的结果,合并成一个结果集

sql1查询出N行

sql2查询出M行

sql1 union sql2 得到N+M行

场景:

2条语句,各自的where条件非常复杂,可以简化成简单条件,再union

union必须满足1个条件:

各语句取出的列数必须相同。列名称未必要一致,列名称会使用第一条sql

语句的列名称为准。

注意:

使用union时,完全相等的行,将会被合并,合并是比较耗时的。

一般不让union进行和平,使用’union all’可以避免合并。

讨论:union的子句中,不用写order by

sql合并后得到的总的结果可以order by,子句order by失去意义

select id,sum(num) from (select id,num from a

union all

select id,num from b) as temp

group by id;

建表过程

建表的过程就是声明列的过程

create table t1 (
sn int,
name varchar(20)
);

列选什么类型的列?
列给什么样的属性?


建表语句

create table 表名 (
列1 列类型[列属性 默认值],
列2 列类型[列属性 默认值],
...
列n 列类型[列属性 默认值],
)
engine = 存储引擎
charset = 字符集


列类型

数值型:

- 整型

- 浮点型

- 定点型

字符串:

- char

- varchar

- text

日期时间类型:

- 2012-12-23

- 14:34:56

整型列

字节,英文Byte,简写B,一般称作“大B”,以跟“小b”(位)区别。

一个字节可以存1个ASCII码(就是纯英文字符数字符号之类)或者半个汉字。

一个字节可以存8位二进制数,所谓1B=8b就是这意思。

运营商高呼:俺的宽带100M,其实是100Mb,还要除以8才变成大家熟悉的MB。

int 1 4个字节

一个字节有8个位

00000000 00000000 00000000 00000001

11111111 11111111 11111111 11111111 2^32-1

bigint 8字节

int 4字节

mediumint 3字节

smallint 2字节

tinyint 1字节,默认带正负号

create table t2 (
num tinyint
);

insert into t2 values(255); // query ok,但其值是127
insert into t2 values(127); // query ok
insert into t2 values(-255); // query ok,但其值是-128
insert into t2 values(-128); // query ok

证明:tinyint 默认带正负号

但是如果我们存储年龄,不需要负数,不想浪费一半的存储空间?
答:见下面unsigned


整型列的属性

unsigned 无符号的,修饰列,列的值从0开始,不为负

alter table t2 add unum tinyint unsigned;
insert into t2 values(3,255); // query ok
insert into t2 values(4,-1); // query ok,但其值是0


zerofill 适合用于学号,编码等,固定宽度的数字,可以用0填充至固定宽度

学号-》1 =》0001

学号-》123 =》0123

思路:zerofill填充至多宽?M

注意:zerofill默认设置列是unsigned, M参数必须配合zerofill使用

alter table t2 add sn tinyint(5) zerofill;
insert into t2 values (4,4,3);
insert into t2 values (4,4,33);
insert into t2 values (4,4,333);


浮点列

float(M,D); M是精度,总位数, D是标度,小数点后面的位数

double与float区别在范围上

decimal

create table t3 (
salary float(5,2)
);

insert into t3 values(9999); // query ok,1警告,但其值是999.99
insert into t3 values(999.99);


create table t4 (
f float(9,2),
d decimal(9,2)
);

insert into t4 values (1234567.23,1234567.23);

+------------+------------+
| f          | d          |
+------------+------------+
| 1234567.25 | 1234567.23 |
+------------+------------+

float/double: 有精度损失
decimal: 定点型,更精确


字符型列

char

varchar

text/blob

enum检举型,是定义好,值就在某几个枚举范围内,

不在枚举范围内可以插入,但其值是空字符串

char(10) // 最多能存10个字符
如果给其一个字符,但其占用10个字符的宽度

varchar(10) // 最多也是能存10个字符
如果给其一个字符,

create table t5 (
n1 char(10),
n2 varchar(10)
);

insert into t5 values(' hello ',' hello ');

// 取出
select concat('!',n1,'!'),concat('!',n2,'!') from t5;
+--------------------+--------------------+
| concat('!',n1,'!') | concat('!',n2,'!') |
+--------------------+--------------------+
| ! hello!           | ! hello !          |
+--------------------+--------------------+

char型,如果不够M个字符(注意是字符,不是字节),
内部用空格补齐,取出时再把右侧空格删掉
这意味着:如果右侧本身有空格,将会丢失。

create table t7 (
gender enum('men','women')
);

insert into t7 values ('men');
insert into t7 values ('women');
insert into t7 values ('yao');


Blob是二进制类型,用来存储图像,音频等二进制信息。

意义:2进制,0-255都有可能出现

Blob在于防止因为字符集的问题,导致信息丢失。

比如一张图片中有0xFF字节,这个在ascii字符集认为非法,在入库的时候,被过滤掉了。

日期时间类型

Year年(1字节) [1901,2155]

Date日期 1998-12-23

范围:1000/01/01,9999/12/31

datetime时期时间 1998-12-31 13:45:43

范围:1000/01/01 00:00:00,9999/12/31 23:59:59

时间戳:

是1970-01-01 00:00:00到当前的秒数

create table t8 (
yq year,
dt date,
tm time,
dttm datetime
);

insert into t8 (yq) values (1901);

insert into t8 (dt) values ('1990-11-12');

insert into t8 (tm) values ('16:20:23');

insert into t8 (dttm) values ('1990-11-12 16:20:23');


列的默认值

1:NULL查询不便

2:NULL的索引效果不高

所以实用中,避免列的值为NULL

如何避免:not null default xx

create table t9 (
id int not null default 0,
name char(10) not null default ''
);

insert into t9 values (1,'lisi');
insert into t9(id) values (2);


主键与自增

主键 primary key 此列不重复,能够区分每一行

// 声明方式1
create table t10 (
id int primary key,
name char(2)
);

// 声明方式2
create table t11 (
id int,
name char(2),
primary key(id)
);

insert into t11 values (1,'lisi');// 再插入一次

// 一张表只能有一列为zuto_increment,且此列必须加索引(index,key)
create table t12 (
id int auto_increment,
name char(2),
key id(id)
);

create table t13 (
id int primary key auto_increment
);


综合建表案例

id用户名性别体重(KG)生日工资上次登录个人简介
idUsernamegenderweightbirthsalarylastLoginintro
列名称列类型默认值是否主键
idint unsignedPRI
UsernameVarchar(20)
genderchar(1) tinyint/enum(‘男’,’女’)
weighttinyint unsigned
birthdate
salarydecimal(8,2)
lastLogindatetime
introvarchar(1500)
这张表不够好,可以优化

分析:这张表除了username/intro列之外,每一列都是定长的

我们不妨让其所有列都定长,可以极大提高查询速度

列名称列类型默认值是否主键
idint unsignedPRI
Usernamechar(20)
genderchar(1) tinyint
weighttinyint unsigned
birthdate
salarydecimal(8,2)
lastLoginint unsigned
introvarchar(1500)
Username char(10) 是会造成空间的浪费,但是提高了速度(值得)

intro char(1500) 却浪费的太多了,另一方面,人的简介,一旦注册完,该的频率也不高。

我们可以把intro列单独拿出来,放到另一张表里。

列名称列类型默认值是否主键
idint unsignedPRI
introvarchar(1500)
在开发中,会员的信息优化往往是把频繁用到的信息,优先考虑效率,存储到一张表中

不常用的信息和比较占据空间的信息,优先考虑空间占用,存储到辅表中。

定长与变长分离

常用与不常用分离

create table user (
id int unsigned primary key auto_increment,
username char(10) not null default '',
gender tinyint not null default 0,
weight tinyint unsigned not null default 0,
salary decimal(8,2) not null default '000000.00',
lastLogin int unsigned not null default 0
)

create table infomation (
id int unsigned primary key auto_increment,
username char(10) not null default '',
intro varchar(1500) not null default ''
)

rename table infomation to intro


列的增删改

alter table 表名 add 列名 列类型 列属性…默认在表的最后

alter table 表名 add 列名 列类型 列属性…after 列名(将会出现在列名后)

alter table 表名 drop column 列名

alter table 表名 change 列名 把改列名变为其他的名称 列属性

alter table 表名 modify 列名 新属性

alter table user add height tinyint unsigned not null default 0; // 增

alter table user drop column height; // 删

alter table user add height tinyint unsigned after weight; // 放在某列之后

alter table user change height shengao smallint; // 修改

alter table user modify height tinyint;


视图 view

视图的概念及建立视图

view: 又被称为虚拟表,view是sql语句的查询结果

select goods_id,goods_name,market_price-shop_price as sheng from goods;

||
\/

create view vgoods as select goods_id,goods_name,(market_price - shop_price) as sheng from goods;

||
\/

select * from vgoods;  //结果等于第一行最上面sql语句的效果


有什么好处?

1. 权限控制时可以用

比如某几个列,允许用户查询,其他列不允许

可以通过视图,开发其中一列或几列,起到权限控制的作用

create view v2goods as select goods_id,goods_name,shop_price from goods;

select * from v2goods; // 只能查到这三列


简化复杂的查询

查询每个栏目下商品的平均价格,并按平均价格排序,查出前三高的

select cat_id,avg(shop_price) as pj from goods group by cat_id;

create view v3goods as select cat_id,avg(shop_price) as pj from goods group by cat_id;

select * from v3 order by pj desc limit 0,3;


视图能不能更新和删除,添加?

如果视图的每一行是与物理表一一对应的,则可以

view的行是由物理表多行经过计算得到的结果,view是不可更新的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息