[关闭]
@Macux 2017-12-14T12:44:41.000000Z 字数 14960 阅读 1396

MySQL 学习笔记

MySQL



1、基础知识

1.1 启动MySQL

  1. mysql --local-infile=1 -u root -p
  2. # 更简单的方法是:创建一个.cnf文件.

1.2 导入本地数据

  1. use sampdb
  2. # 选择当前的数据库为"sampdb".
  3. load data local infile '/etc/mysql/ryan.txt' into table ryan fields terminated by ';' lines
  4. terminated by '\n';
  5. # 用';'区分不同字段,用'回车'区分不同的record.

1.3 创建一张数据表

  1. create table president(
  2. last_name varchar(15) not null,
  3. first_name varchar(15) not null,
  4. sex enum('F','M') not null,
  5. city varchar(20) not null,
  6. state varchar(2) not null,
  7. birth date not null,
  8. death date not null,
  9. president_id int unsigned not null auto_increment,
  10. primary key (president_id)
  11. ) engine = InnoDB; # 在MySQL中,只有"InnoDB"才支持外键功能.

1.4 show与desc语句

  1. show tables;   # 输出当前数据库所有的表.
  2. desc president;  # 查看表的结构.

2、常用的SQL语句

2.1 基本语法

  1. select select_list # What columns to select.
  2. from table_list # The tables from which to select rows.
  3. where row_constraint # What conditions rows must satisfy.
  4. group by groupint_columns # How to group results.
  5. order by sorting_columns # How to sort results.
  6. having group_constraint # What conditions groups must satisfy.
  7. limit count; # Row count limit on results.

2.2 对查询结果进行排序

  1. select * from president order by if (death is null, 0 ,1),death desc;
  2. # 先用if()语句,根据0,1进行升序排列;
  3. # 再用order by death desc(降序),在进行一次排序;
  4. # 查询结果是:按照总统逝世日期降序排列,且让健在的总统排在最前面.

2.3 限制查询结果中数据行的个数

  1. select * from president order by birth limit 10;
  2. # 输出前10个record.
  3. select * from president order by birth limit 10,5;
  4. # 跳过前10个record后,输出紧跟的5个.
  5. select * from president order by birth order by rand() limit 10;
  6. # 随机抽出10条record.

2.4 输出列进行求值和命名

  1. select concat(first_name,'',last_name) as 'President Name',concat(city,',',state) as 'Place of Birth' from president;

2.5 日期

  1. select * from president where month (birth) = month(curdate()) and dayofmonth(birth) = dayofmonth(curdate());
  2. # 输出'今日出生'的总统信息.
  3. select concat(first_name,''last_name) as 'President Name' ,timestampdiff(year,birth,death) as 'age' from president where death is not null order by age desc limit 10;
  4. # 降序输出已故总统中,寿命最长的前十位的姓名和年龄.
  5. select * from president where death >= '1970-1-1' and death < date_add('1970-1-1',interval 10 year);
  6. # 输出逝世于20世纪70年代的总统信息.

2.6 模式匹配

  1. select * from president where last_name like 'W%';
  2. # 输出姓氏以字母W或w开头的总统信息.
  1. select * from president where last_name not like '%W%';
  2. # 输出姓氏里不含有W或w字母的总统信息.
  1. select * from president where last_name like'____'; # 四个下划线.
  2. # 输出姓氏由且仅有4个字母构成的总统信息.
  1. select 'ryanfan' regexp '[fanpeng]'; # [...]匹配在方括号里的任何一个字符.
  2. # 此处返回'1'.
  1. select * 'kobebryant' regexp '^kobe'; # 匹配以'kobe'开头的字符串.
  2. select * 'wanglihong' regexp 'hong$'; # 匹配以'hong'结尾的字符串.
  3. select * 'wuyuetian' regexp '^wuyuetian$' # 匹配字符串仅是'wuyuetian'的情况.

2.7 设置SQL变量

  1. select @birth := birth from president where last_name = 'Jackson' and first_name = 'Andrew';
  2. select * from president where birth < @birth order by birth;

2.8 生成统计信息

  1. select distinct state from president order by state;
  2. # 用关键字distinct把重复的record清除掉.
  3. select count(*) from president where last_name = 'Jackson';
  4. # 用count(*)输出符合条件的全部record,但是count()只能统计非NULL值的个数. 'But,在Teradata中,count在计算中是包含NULL的!'
  5. select sex, count(*) as 'Count' from president group by sex order by Count desc with rollup;
  6. # 分别统计出不同性别的总统人数,并根据人数降序输出。并且多输出一行,统计二者的和.
  7. select month(birth) as 'Month',monthname(birth) as 'Month_Name',count(*) as count from president group by Month_Name order by Month.
  8. # 根据不同出生月份的总统人数进行分组,并按照从1月-12月的顺序输出.
  9. select state, count(*) as 'Count' from president group by state having count > 1 order by Count desc;
  10. # 输出哪些state是有两位或两位以上的总统.
  11. # "having count = 1" 表示不重复的值.
  12. # "having count ≠ 1" 表示某个数据列重复出现的值.

3、使用SQL管理数据

3.1 SQL模式

  1. set (global) seq_mode = "xxxxx";

3.2 存储引擎的介绍

具备事务处理的数据库,可以确保在事务处理不成功时,数据可以滚回。

  1. show engines\G
  2. # ';'结尾 :常规输出.
  3. # '\G'结尾:按行输出.
  4. # '\g'结尾:按列输出.
  1. show create table president\G

3.3 DataBase的常用操作

  1. create database db_name;
  1. drop database db_name;
  1. alter database db_name character set xxxx collate yyyy;

3.4 重要的SQL语句

  1. alter database sampdb default character set 'gbk';
  2. set names 'gbk';
  3. create table lenovo (name varchar(100) not null,id int unsigned not null);
  4. insert into lenovo values('电脑','200'),('笔记本','123');
  1. update member set email='ryanfan0313@163.com',street='123 Elm St',zip= '510520' where last_name = 'Fan' and first_name = 'Ryan';
  1. delete from tbl_name where.....;
  2. # 删除表中符合筛选条件的某几行.
  1. truncate table tbl_name;
  2. # 清空数据表,保留表结构.
  1. create temporary table tbl_name ... ;
  • temporary数据表的名字允许与一个现有的永久性数据表相同。例如:
    如果你在sampdb数据库创建了一个名为zhihui的temporary数据表,原有的zhihui数据表将被隐藏起来,对zhihui数据表的访问将只作用于新建的temporary数据表。比如执行drop table zhihui语句,被删除的将是temporary数据表。

(1)、利用子查询直接复制

  1. create table president_copy select * from president (where sex = 'F');

(2)、先输入一行record,然后借用cast()函数设置字段类型

  1. create table tbl_name select cast(1 as unsigned) as i,cast(curtime() as time) as t,cast(pi() as decimal(10,6)) as d;

(3)、创建表的同时,顺便插入一行record。(它比方法2更加的全面,因为可以对字段进行更详细的设置。)

  1. create table tbl_name(i int unsigned not null,t time not null,d decimal(10,6)) select 1 as i,cast(curtime() as time) as t,cast(pi() as decimal(10,6)) as d;

(4)、最懒的方法

  1. create table tbl_name select 1 as i,curtime() as t,pi() as d;
  1. alter table tbl_name engine = xxxx;
  1. alter table tbl_name add column_name varchar(100);
  2. alter table tbl_name drop column column_name;
  1. alter table tbl_name change i j varchar(100) not null;
  2. # 把字段名为'i'的名字改为'j',并把字段属性修改为varchar(100) not null.
  1. alter table tbl_name auto_increment = 100;
  1. alter table tbl_name rename to new_tbl_name;
  2. # 更简单的重命名table的方法:
  3. rename table tbl_name to new_tbl_name;
  • alter的全部用法,请参见《MySQL技术内幕》P747。
  1. show status from db_name (where name = 'ryan')\G
  2. # 输出数据库中每一张table的基础信息,这些信息偏向table本身,比如创建时间等等.
  3. select * from infromation_schema.tables where table_schema = 'sampdb' and table_name = 'ryan'\G
  4. # 输出数据库中某一张具体table的基础信息,效果和'show status from db_name (where name = 'ryan')\G'一样.
  5. show create table ryan\G
  6. # 输出的表内部结构的信息,字段、存储引擎等等.
  1. show index from tbl_name;
  1. show tables;
  1. set profiling = 1;
  2. 多条SQL语句
  3. show profiles;

(1)、内联结(只显示在两个数据表里都能找到匹配的数据行)

  1. select t1.*,t2.* from t1 inner join t2 where t1.i1 = t2.i2;

(2)、外联结(除了显示同样的匹配结果,还可以把其中一个数据表在另一个数据表里没有匹配的数据行也显示出来,分为左联结右联结

  • 工作原理:给定用来匹配两个数据表里的数据行的数据列,除了输出二者匹配的那些数据行,还会把左数据表在右数据表里没有匹配的数据行也显示出来。当右数据表的某些数据列未被定义为"Not Null",那么一个缺失值的record,也会被认为是'未匹配'。
    此处输入图片的描述

  • 必要性:在使用左联结的时候,就表示左数据表里的数据是绝对需要的,join右数据表只是为了补充说明,满足联结条件or不满足,都是一种说明。

  1. select t1.*,t2.* from t1 left join t2 on t1.i1 = t2.i2 where t2.i2 is null;
  2. # 当加上'where t2.i2 is null'后,输出的全是那些没有匹配的record,这有可能在实际运用中需要的.

(1)、"子查询(subquery)":把一条select语句用括号括起来,并嵌入另一个select语句。

(2)、子查询测试:

1.标量子查询(只产生一个值)的结果,可以用'='、'<>'、'>'、'>='、'<'、'<='操作符进行相对值求值比较;

  1. select * from score where event_id = 5 and score > (select avg(score) from score where event_id =5);

2.'in'、'not in'测试某给定值是否包含在子查询的结果集里;

  1. select * from president where (city,state) not in (select city,state from president where last_name = 'Roosevelt');

3.'all'、'any'/'some'把某给定值与子查询的结果集进行比较;

  1. select * from president where birth <= all (select birth from president where last_name = 'Roosevelt');
  2. # 输出出生日期小于或等于last_name为'Roosevelt'出生日期的所有数据行.
  1. select * from president where (city,state) = any (select city,state from president where last_name = 'Roosevelt');
  • 用'all'的情况一般是筛选条件只有一个(birth),用any/some的情况一半筛选条件是多个,只要满足其中一个就输出数据行。

4.'exists'、'not exists'测试子查询的结果集是否为空。

  1. select exits (select * from absence);

5.个人认为'子查询'实在太臃肿了,可以用'外联结'的时候还是用'外联结'吧!*

  • 作用:把多个查询的结果合并在一起创建一个结果集。

  (1)、union结果集里的数据列名字来自第一个select语句里的数据列的名字。

  1. select i, c from t1 union select i, d from t3;
  2. # 输出结果中,只有两个字段,名字分别是'i'和'c'.

  (2)、default下,union将结果集中的重复数据行剔除,可以设置union all 来保留重复数据行。

  1. select * from t1 union all select * from t2 union all select * from t3;

  (3)、借助order by和limit对结果进行优化

  1. (select i, c from t1) union (select i, d from t3) order by c limit 8;
  1. (select * from t1 order by i limit 2) union (select * from t2 order by c limit 3) union (select * from t3 order by d limit 3);
  • 如果要选取某给定数据表的一个子集,将它定义为一个视图,则可以一劳永逸。
  1. create view tera(new_name1, new_name2, new_name3, new_name4) as select last_name, first_name, city, state from president;
  2. # 下次再要引用'last_name', 'first_name', 'city', 'state'这四个字段时,直接从tera中调用就更为简便.

1.绕口的概念:

'事务'是作为一个不可分割的逻辑单元而被执行的一组SQL语句,如有必要,它们的执行效果可以被撤销。这是因为并非所有的语句每次都能执行成功,有些语句还会对数据产生永久性影响。

2.工作原理:

事务处理是通过'提交(commit)'和'回滚(rollback)'功能实现的。'提交'将那些语句的执行效果永久性地记录到数据库里,'回滚'将发生错误之前已经执行完的语句的效果全部撤销掉。

3.总结:

(1)、一旦发起'start transaction',即所有的SQL语句会隐式自动提交一个事务。但若以rollback结尾,将全部撤销。

  1. start transaction;
  2. insert into zhihui set name = 'Leehom';
  3. insert into zhihui set name = 'junjun';
  4. select name from zhihui; # 会输出'Leehom'和'junjun'两行record.
  5. rollback;
  6. select name from zhihui; # 'Leehom'和'junjun'消失了.

(2)、如果'set autocommit = 1',即所有的SQL语句都会永久性的改写数据库,怎么rollback都没用。
(3)、如果'set autocommit = 0',你不commit,都可以用rollback来撤销。

4.利用'保存点(savepoint)'进行部分回滚:

  1. start transaction;
  2. insert into zhihui set name = 'Leehom';
  3. savepoint my_point1;
  4. insert into zhihui set name = 'junjun';
  5. rollback to my_point1;
  6. insert into zhihui set name = 'yuanyuan';
  7. commit;
  8. select name from zhihui;
  9. # 将会输出'Leehom'、'yuanyuan'.
  1. lock tables inventory write;
  2. update inventory set quantity = 44 where item = 'shirt';
  3. unlock tables;

(1)、'on delete no action'&&'on delete restrict':含义与省略'on delete'子句一样;
(2)、'on delete cascade'子句,删除父表数据行时,子表里与之相关联的数据行也将被删除;
(3)、'on delete set null'子句,删除父表数据行时,子表里与之相关联的数据行将被设置为NULL。

(1)、父表的索引必须列出references子句里的数据列,子表里的索引必须列出外键数据列;
(2)、父表和子表索引对应的数据列,必须是兼容的数据类型;
(3)、不能对外键关系里的字符串数据列的前缀编制索引。

  1. create table parent(
  2. par_id int not null,
  3. primary key(par_id)
  4. ) engine = 'InnoDB';
  1. create table child(
  2. par_id int not null,
  3. child_id int not null,
  4. primary key (par_id,child_id),
  5. foreign key (par_id) references parent (par_id)
  6. on delete cascade
  7. on update cascade
  8. ) engine = 'InnoDB';
  • 要想对某个table进行全文搜索,必须实现为它创建一个'fulltext'索引,该索引具有如下特点:

(1)、fulltext索引只能由char、varchar和text这几种类型的数据列构成;
(2)、全文搜索将忽略'常见'(50%规则,即至少在一半的数据行里都出现过)的单词;
(3)、主动忽略一些'休止单词',例如'the'、'after'等;
(4)、太短(少于4个字符)的单词将会忽略;
(5)、此处的'单词'是指由'字母'、'数字'、'’'和'_'构成的字符序列。'full-blood'将被解释为'full'和'blood'两个单词。

A、自然语言模式:

  • 'match()'操作符列出将被搜索的数据列,'against()'给出搜索字符串。
  1. select * from ryan where match(phrase) against('hard soft');
  2. # 把包含'hard'或者'soft'的数据行找出来.

B、布尔模式:

  • 特别之处:
    a、'50%规则'不再起作用;
    b、查询结果不再按照相关度排序;
    c、搜索短语时,用双引号括起来,表示按照给定顺序排列,才算匹配。
  1. select * from ryan where match(phrase) against('"bell book and candle"' in boolean mode);
  1. select * from ryan where match(attribution,phrase) against('+bell -candle' in boolean mode);
  2. # 匹配只包含'bell',不包含'candle'的数据行.
  3. select * from ryan where match(phrase) against('soft*' in boolean mode);
  4. # 匹配以包含'soft'开头的数据行.

C、查询扩展模式:

  1. select * from ryan where match(attribution,phrase) against('bell book' with query expansion)
  2. # 工作原理:第一阶段进行自然语言搜索,结束后发现'candle'这个词是第一阶段中相关程度最高的数据行里的单词,于是将'candle'用在搜索的第二阶段.

4、数据类型

4.1 疑难杂症

  1. insert into zhihui values('He said,"I told you so."');
  2. # 用与'字符串中的引号字符'不同的引号把整个字符串括起来.
  1. set @s1 = 'ryan';
  2. select length(@s1), char_length(@s1);
  3. # length()测量'字节'个数,char_length()测量'字符'个数.
  1. create table train(id int(12) zerofill);
  1. create table ryan (preference set('Snooker','Data Mining'));
  2. insert into table values('Big Data Mining');
  3. # 'Big'将被剔除,'Data Mining'被插入数据库.

4.2 用途广泛的AUTO_INCREMENT属性

  1. alter table ryan auto_increment = 666;
  2. # 或者
  3. create table(.....) engine = MyISAM auto_increment= 666;
  • 重新编排纯属是强迫症患者的批号,虽然工作很容易完成,然并卵。因为重新编排在性能上不会有任何改进,而且调整该数据列的顺序将会破坏表与表之间的对应关系。
    故此处不贴出重新编排的代码。

4.3 选用数据类型时应该思考的问题

  1. select * from ryan procedure analyse()\G
  2. # 该语句用于帮助判断是否可以选用一种更'小'的类型,以改善数据表查询性能并减少数据表的存储空间占用量.

5、查询优化

  • '查询优化'主要是从语法上和硬件上两方面进行,硬件不用多说,让内存尽量大,让CPU尽量牛逼轰轰等等。语法上主要是通过'创建索引'和'查询优化程序'两个方面。

5.1 使用索引

(1)、快速检索 当一张table有索引时,则这张table已经被索引'分类',那么这张table比不带索引的table,就显得更"小"了。
(2)、快速定位 当一张table带有索引时,进行检索时,不需要从第一行进行线性扫描,而是直接找到第一个匹配项

(1)、如果某个索引是PRIMARY KEY或是SPATIAL时,带索引的数据列必须具备NOT NULL属性;
(2)、'PRIMARY KEY'和'UNIQUE'的区别:
A、每张table只能有一个PRIMARY KEY(当然也可以是组合主键);
B、PRIMARY KEY不可以包含NULL,而UNIQUE索引可以包含NULL;

(1)、主键是逻辑模型的概念主索引是物理模型中用于数据分配和存取的物理机制
(2)、主键没有属性数目限制主索引最多由16个属性组成
(3)、主键在逻辑模型中定义主索引在创建表或单独定义
(4)、主键取值必须唯一主索引可以唯一也可以不唯一
(5)、主键用来区分数据记录主索引用来进行数据分配
(6)、主键的值不会改变主索引的值可以变化
(7)、主键不可以为空值主索引可以为空值

  1. alter table tbl_name add index/unique/... index_name (index_columns);
  2. # 创建索引.
  1. show index from tbl_name;
  2. # 查看数据表的索引.
  1. alter table tbl_name drop index/primary/.... index_name;
  2. # 删除索引.

5.2 查询优化程序

  • So,它主要是为了帮我们做两件事:
    (1)、当哪些数据行有索引时,可以提升查询速度;
    (2)、现在的查询语句有没有被优化的必要。
  1. explain select * from member where to_days(expiration) < 30 + to_days(curdate())\G
  • 关于输出结果的解释,,请参见《MySQL技术内幕》P776。

5.3 数据类型也会影响查询效率

  1. select * from tbl_name procedure analyse(16,256);
  2. # 如果数据列的不同取值在16个以上或者长度超过256字节,则不提出ENUM类型建议.
  1. optimize table tbl_name;
  2. # 当数据库在删除大量的数据后,数据文件大小可能仍未变小,这是由于删除操作后数据文件留下所致.

6、使用Python操作MySQL

  1. import MySQLdb
  2. # 连接数据库
  3. conn = MySQLdb.connect(host='localhost', user='root', passwd='root', db='test', port=3306,charset='utf8') # charset属性,用来避免中文乱码,必须要跟数据库的编码一样
  4. cur = conn.cursor()
  5. # 用Python执行SQL语句
  6. cur.execute('create database if not exists python')
  7. conn.select_db('python')
  8. cur.execute('create table test(id int,info varchar(20))')
  9. values = []
  10. for i in range(20):
  11. values.append((i,'Ryan' + str(i)))
  12. cur.executemany('insert into test values(%s,%s)',values) # 插入多条数据
  13. data = [123,'Fan']
  14. cur.execute('insert into test values(%s,%s)',data) # 插入一条数据
  15. conn.commit() # 一定要有这句来提交事务,否则不能成功插入数据。
  16. count = cur.execute('select * from test')
  17. print 'there has %s rows record' % count
  18. cur.close()
  19. conn.close()
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注