增加(Create)
检索(Retrieve)
更新(Update)
删除(Delete)
上面抽象意义的概括,如果用具体的sql命令简写表示,则为IDUS
1)增(INSERT)
INSERT into tableName (col1,col2...coln) values (value1,value2...valuen);
当然,如果能保证是全值插入,则可以省略tableName后面的列名(但values不能省):
INSERT into tableName values (value1,value2...valuen);
1)tableName后面的列名用于部分值插入时,将values的值对应到列中去,如
insert into tableName(col1,col3,col5) values(value1,value2,value3);
就将values(value1,value2,value3)分别插入到tableName的第1,3,5列中去了。
这里提一句:那么没有指定的列的值怎么办?——按照定义表时列的default 值来自动填入,如果没有默认值但是允许为NULL则填入NULL值。如果定义表时既没有指定默认值,也没有允许为空(NOT NULL),怎么办?
会报错。。。。此条insert语句不能成功执行,插入记录失败。
2)如果指定的列(tableName后面的列名)中有主键列,则插入值一定要保证不与已经存在的主键重复
若 insert into tableName(col3,col1,col5) values(value1,value2,value3); 中col1,col2,col3没有一个是主键列,则插入时,MySQL会使用设计表时的auto_increment策略:
但是,如果insert into tableName(col3,col1,col5) values(value1,value2,value3); 指定列中存在主键列,现在假设col1是主键列,则要保证value2与表中已经存在的主键不重复,否则会插入失败,报错:
插入id为1失败:
如果与与表中已经存在的主键不重复,则会成功,如插入id = 3:
并且以后都是从3往后递增:
值得注意的是,此时回头看
“insert into tableName(col3,col1,col5) values(value1,value2,value3);” 指定列中存在主键列
是可以插入中间“空闲的id”的,e.g:
用户
但是,此时不指定id的insert还是会从6开始,而不是2。即MySQL自己为维持一个最大指针,如果使用auto_increment,而不是用户指定id,则从这个最大指针往后追加。
综上所述,MySQL的策略是这样的:如果指定了主键自增(id int(11) NOT NULL primary key auto_increment;),则:
若用户指定id,则检查表中是否已经存在,不重复才会插入,并且如果此指定id大于当前最大id指针,则更新此最大id指针,相当于中间的id都skip掉了;
若不指定id,则MySQL自己添加id,规则追加在维持的最大id指针的后面。
可以看到,MySQL支持利用间隙之间的id,也支持直接skip掉一段id,但是这个只是MySQL提供的灵活性,在实际应用中,尽量避免用户自己指定id的情况,数据库数据的完整性不能由用户数据来保证,不管什么什么情况都应该使用主键自增的设定,并且插入时使用不指定id的插入方式(insert into tableName(col3,col1,col5) values(value1,value2,value3);中的col不应该有主键列)。
2)删(DELETE)
DELETE from tableName [WHERE Clause];
前面有个细节:where cause使用方括号 [] 包围起来的——是可选的,即可以不使用,那么delete变成了:
DELETE from tableName;
这代表删除这张表中的所有数据,注意不是删除表:
但是注意, delete不会重置主键,主键自增的属性使下次insert时接着上次最大的id+1开始:
如果想清空表并且重置主键可以使用 truncate命令:
TRUNCATE table tableName;
但是注意,这个命令要慎用,要保证需求是删除全部数据而不是删除一部分,并且以后永远不不着这部分数据;另外,本表中的id不是任何其他表的外键,不然一旦删除从1重新开始,会使其他表连接到本表的新数据,这会导致严重错误。
3)改(UPDATE)
UPDATE table_name SET field1=new-value1, field2=new-value2 [WHERE Clause];
其实和DELETE很像,可以使用WHERE子句更新特定行,也可以不使用WHERE子句更新所有行:
特定行:
所有行:
一个很有趣的问题是:能update主键的值吗?
试试便知:
成功了,可以想见,改成7也是可以的。
其实update就是将特定的值重新赋值的过程,机制相当于INSERT,只是代价更小,只用更新特定的列即可。
但是,修改id同样是强烈不推荐的,这个insert不指定id是一个道理。
4)查(SELECT)
单表查询:
select是最复杂的语句,先看单表查询:
select col1,col2... from tableName [WHERE Cacuse];
当然,可以对查出的列作各种“运算”:拼接字符串Concate,统计个数count,求最大值max,起别名AS等等。
多表查询:
内连接 inner join(MySQL的默认连接方式:join 就是inner join)
准备两张表:家长表和学生表
parent:
student:
可以看到,Chenwei的孩子Tom,Wangjianguo的孩子Jerry,Lilin的孩子HH。
使用inner join:
要注意语法,很容易错误,如果是select * from 内连,则全部列都被列出来:
左连接 left join(左表所有记录都在,右表没有的为NULL)
一定要注意顺序,另外也要注意一些“潜规则”:
① select顺序不影响left join,但是Concat会影响
以某一键(上例中id)进行左连接,是从左表中按顺序拿出一个个id(遍历)去右表中查找有无记录,这样做最终的结果里必然是左表中的记录肯定有(除非select的刚好是NULL的记录),右表中不一定有(NULL)。select的顺序并不会影响结果。
为了更形象地展示,还是上面的例子,将select s.name, p.name 换成 select p.name,s.name:
看下原始列值和Concat拼接结果:
select s.name,s.name
select p.name,s.name
即concate任意一列为null时,直接返回结果null,而不是带有部分值的结果。
② A a left join B b 等于 B b right join A a
不多说,明显是对的
右连就是左连,不多说
不使用join实现连接:
① 使用from多表+where替代on
select p.name,s.name from parent p,student s where p.childid = s.id;
② 子查询
但是子查询方式下,主select“看不见”子select的信息,所以上面只能取到p.name,不能拿到s.name:
显而易见,也可以使用EXISTS:
这里还稍微再po一下IN和EXISTS的区别:
可以看到,IN是先扫描外表,再进内表
EXISTS是先扫描内表,再扫外表。