Linux下mysql学习笔记二

多表查询

      前面我们讲解的mysql表的查询都是对一张表进行查询,在实际开发中这远远不够。下面我们用一个简单的公司管理系统,有三张表EMP,DEPT,SALGRADE来演示如何进行多表查询

    查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J

            mysql> select * from EMP where (sal>500 or job='MANAGER') and ename like 'J%';

    按照部门号升序而雇员的工资降序排序
            mysql> select * from EMP order by deptno, sal desc;
     使用年薪进行排序
            mysql> select ename, sal*12+ifnull(comm,0) as ' 年薪 ' from EMP order by 年薪 desc;

    1、分页查询        select 字段 from 表名 where 条件 limit 起始位置,记录条数

             按雇员的empno号升序取数,每页显示3条记录。请分别显示第一页,第二页,第三页

                        mysql> select * from EMP order by empno limit 0, 3;
             显示工资最高的员工的名字和工作岗位
                        mysql> select ename, job from EMP where sal = (select max(sal) from EMP);
            显示工资高于平均工资的员工信息
                        mysql> select ename, sal from EMP where sal>(select avg(sal) from EMP);
            显示每个部门的平均工资和最高工资
                        mysql> select deptno, format(avg(sal), 2) , max(sal) from EMP group by deptno;
            显示平均工资低于 2000 的部门号和它的平均工资
                        mysql> select deptno, avg(sal) as avg_sal from EMP group by deptno having avg_sal<2000;
            显示每种岗位的雇员总数,平均工资
                        mysql> select job,count(*), format(avg(sal),2) from EMP group by job;

    2、自连接

            自连接是指在同一张表连接查询。显示员工FORD的上级领导的姓名。这个没有用多表,用的是子查询:mysql> select ename from EMP where empno=(select mgr from EMP where ename='FORD');

     3、子查询

            子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询

    4、单行子查询    

                返回一行记录的子查询。显示SMITH同一部门的员工    mysql> select * from EMP WHERE deptno = (select deptno from EMP where ename='smith');

    5、多行子查询

                返回多行记录的子查询,使用关键字in。如何查询和10号部门的工作相同的雇员的名字,岗位,工资,部门号,但是不包含10自己的    mysql> select * from EMP where job in ( select distinct job from EMP where deptno=10) and deptno <> 10;

            在多行子查询中使用all操作符。显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号:    

                    mysql> select ename, sal, deptno from EMP where sal > all(select sal from EMP where deptno=30);

            在多行子查询中使用any操作符。显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号:    

                    mysql> select ename, sal, deptno from EMP where sal > any(select sal from EMP where deptno=30);

    6、多列子查询

            单行子查询是指子查询只返回单列,单行数据,多行子查询是指返回单列多行数据,都是针对单列而言的,而多列

子查询则是指查询返回多个列数据的子查询语句。

    7、from子句中使用子查询
            子查询语句出现在from子句中。这里要用到数据查询的技巧,把一个子查询当做一个临时表使用。
            示例:
                    如何显示高于自己部门平均工资的员工的信息

                -- 获取各个部门的平均工资,将其看作临时表            

                mysql> select ename, deptno, sal, asal from EMP,
                        -> (select avg(sal) asal, deptno dt from EMP group by deptno) tmp
                        -> where EMP.sal > tmp.asal and EMP.deptno=tmp.dt;

                        -> (select avg(sal) asal, deptno dt from EMP group by deptno) tmp
                        -> where EMP.sal > tmp.asal and EMP.deptno=tmp.dt;

        查找每个部门工资最高的人的详细资料
                 mysql> select EMP.ename, EMP.sal, EMP.deptno, ms from EMP,
                         -> (select max(sal) ms, deptno from EMP group by deptno) tmp
                         -> where EMP.deptno=tmp.deptno and EMP.sal=tmp.ms;

        显示每个部门的信息(部门名,编号,地址)和人员数量。
        方法1:使用多表
                 mysql> select dname, DEPT.deptno, loc,count(*) '部门人数' from EMP, DEPT
                        -> where EMP.deptno=DEPT.deptno
                        -> group by DEPT.deptno;

        方法2:使用子查询
                -- 1. EMP表进行人员统计        select count(*), deptno from EMP group by deptno;

                -- 2. 将上面的表看作临时表            

                        mysql> select DEPT.deptno, dname, mycnt, loc from DEPT,

                                -> (select count(*) mycnt, deptno from EMP group by deptno) tmp

                                -> where DEPT.deptno=tmp.deptno;

                                -> (select count(*) mycnt, deptno from EMP group by deptno) tmp

                                -> where DEPT.deptno=tmp.deptno;

    8、自我复制( 蠕虫复制 )

            面使用了多表和子查询两种方式进行查询,到底哪个效率高呢?我们需要弄大量数据来进行测试。可以使用自我
复制创建海量数据。
            示例:

                        把EMP表的数据快速变成160000
                                mysql> create table tmp like EMP; -- 为了做测试,创建tmp
                                mysql> insert into tmp select * from EMP;--EMP表的数据插入到tmp
                                mysql> alter table tmp drop primary key; -- 删除主键属性
                                mysql> insert into tmp select * from tmp; -- 自我复制
                                mysql> select count(*) from tmp; -- 快速的创建了20多万条记录
            删除表中的的重复复记录
                    创建一张表:        mysql> create table tt(id int, name varchar(20))
                
            要求:重复的数据只能有一份
                思路:
                        1. 创建一张空表tmp_tt,空表的结构和tt一样
                                mysql> create table tmp_tt like tt;
                        2.
tt表进行distinct,把数据导入空表tmp_tt
                                mysql> insert into tmp_tt select distinct * from tt;
                        3.
删除tt
                                mysql> drop table tt;
                         4. tmp_tt改名成tt
                                mysql> alter table tmp_tt rename tt;


        9、合并查询
                在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 unionunion all
             union        
该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。
                示例:    
将工资大于25000和职位是MANAGER的人找出来
                    mysql> select ename, sal, job from EMP where sal>2500 union
                            -> select ename, sal, job from EMP where job='MANAGER';--
去掉了重复记录
                union all    该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。
                     mysql> select ename, sal, job from EMP where sal>2500 union all
                             -> select ename, sal, job from EMP where job='MANAGER';

        10、外键

                外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或unique约束。当
定义外键后,要求外键列数据必须在主表的主键列存在或为
null。语法:foreign key (字段名) references 主表()
        11、综合案例
                    有一个商店的数据,记录客户及购物情况,有以下三个表组成:
                        1. 商品goods(商品编号goods_ id,商品名goods_ name, 单价unitprice, 商品类别category, 供应商provider)
                        2.
客户customer(客户号customer_ id,姓名name,住址address,邮箱email,性别sex,身份证card_id)
                        3.
购买purchase(购买订单号order_ id,客户号customer_ id,商品号goods_ id,购买数量nums)
                    要求:
                            每个表的主外键
                            客户的姓名不能为空值
                            邮箱不能重复
                            客户的性别
(男,女)
                    

-- 创建goods表
create table goods(
goods_id int unsigned primary key auto_increment,
goods_name varchar(100) not null default '',
unitprice decimal(10,2) not null default 0.0,
category smallint not null default 0,
provider varchar(100) not null default ''
);
--创建customer
create table customer(
customer_id int unsigned primary key auto_increment,
name varchar(50) not null default '',
address varchar(100) not null default '',
email varchar(60) not null unique,
sex enum('男','女') not null default '男',
card_id varchar(20) not null unique
);
--创建purchase
create table purchase (
order_id varchar(30) not null primary key,
customer_id int unsigned,
goods_id int unsigned,
nums int not null default 0,
foreign key(customer_id) references customer(customer_id),
foreign key(goods_id) references goods(goods_id);
表的内连和外连

       1、内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,我们前面学习的查询都是内连接,也是在开
发过程中使用的最多的连接查询。
        语法:    

发过程中使用的最多的连接查询。
        语法:    
select 字段 from 1 inner join 2 on 连接条件 and 其他条件;
        说明:前面学习的都是内连接
        举例说明:
             显示 SMITH 的名字和部门名称
              -- 用前面的写法
              mysql> select ename, dname from EMP, DEPT where EMP.deptno=DEPT.deptno and ename='SMITH';
               -- 用标准的内连接写法
              mysql> select ename, dname from EMP inner join DEPT on EMP.deptno=DEPT.deptno and ename='SMITH';
        2、 外连接
                    外连接的分类:   分为左外连接和右外连接
                    左外连接:如果联合查询,左侧的表完全显示我们就说是左外连接         
                    语法: select 字段名 from 表名 1 left join 表名 2 on 连接条件
                  右外连接:如果联合查询,右侧的表完全显示我们就说是右外连接。
                 基本语法:  select 字段 from 表名 1 right join 表名 2 on 连接条件;
                 示例:     stu 表和 exam 表联合查询,把所有的成绩都显示出来,即使这个成绩没有学生与它对应,也要显示出来。
                                mysql> select * from stu right join exam on stu.id=exam.id
索引

             1、作用:提高数据库的性能,索引是物美价廉的东西了。不用加内存,不用改程序,不用调sql,只要执行正确
‘create index’,查询速度就可能提高成百上千倍。但是天下没有免费的午餐,查询速度的提高是以插
入、更新、删除的速度为代价的,这些写操作,增加了大量的
IO。所以他的价值,在于提高一个海量数
据的检索速度。

             2、常见索引分为:

                主键索引(primary key),唯一索引(unique),普通索引(index),全文索引(fulltext)--解决中子文索引问题。

             3、索引的基本原理

                    

                索引的说明: (1). 占用磁盘空间
                                     (2). 当添加一条记录,除了添加到表中,还要维护二叉树,速度有影响,但不大。
                                  (3). 当我们添加一个索引,不能够解决所有查询问题,需要分别给字段建立索引;例如 select * from EMP where  ename='abcdef';
                                     (4).
索引是以空间换时间

             4、创建索引   

                    (1). 创建主索引

                            第一种方式:create table user1(id int primary key, name varchar(30));
                                                    --
在创建表的时候,直接在字段名后指定 primary key
                            第二种方式:create table user2(id int, name varchar(30), primary key(id));
                                                    --
在创建表的最后,指定某列或某几列为主键索引

                            第三种方式:

                                                create table user3(id int, name varchar(30));
                                                alter table user3 add primary key(id); --
创建表以后再添加主键
                            主键索引的特点:
                                        1. 一个表中,最多有一个主键索引,当然可以使符合主键
                                        2. 主键索引的效率高(主键不可重复)
                                        3. 创建主键索引的列,它的值不能为null,且不能重复
                                        4. 主键索引的列基本上是int

                    (2).唯一键索引

                            第一种方式:create table user4(id int primary key, name varchar(30) unique);
                                                --
在表定义时,在某列后直接指定unique唯一属性。
                            第二种方式:    create table user5(id int primary key, name varchar(30), unique(name));
                                                --
创建表时,在表的后面指定某列或某几列为unique
                            第三种方式:
                                                    create table user6(id int primary key, name varchar(30));
                                                    alter table user6 add unique(name);
                            唯一索引的特点:
                                    1. 一个表中,可以有多个唯一索引
                                    2. 查询效率高
                                    3. 如果在某一列建立唯一索引,必须保证这列不能有重复数据    
                                    4. 如果一个唯一索引上指定not null,等价于主键索引

                    (3).普通索引的创建

                          第一种方式
                                            mysql> create table user8(id int primary key,
                                                    -> name varchar(20),
                                                    -> email varchar(30),    
                                                    -> index(name) --
在表的定义最后,指定某列为索引
                                                    -> );
                         第二种方式
                                            mysql> create table user9(id int primary key, name varchar(20), email varchar(30));
                                            mysql> alter table user9 add index(name); --
创建完表以后指定某列为普通索引
                        第三种方式 
                                            mysql> create table user10(id int primary key, name varchar(20), email varchar(30));-- 创建一个索引名为 idx_name 的索引
                                            mysql> create index idx_name on user10(name);
                         普通索引的特点:
                                1. 一个表中可以有多个普通索引,普通索引在实际开发中用的比较多
                                2. 如果某列需要创建索引,但是该列有重复的值,那么我们就应该使用普通索引

                (4). 全文索引的创建

                            

当对文章字段或有大量文字的字段进行检索时,会使用到全文索引。MySQL提供全文索引机制,但是有要求,要求
表的存储引擎必须是MyISAM,而且默认的全文索引支持英文,不支持中文。
如果对中文进行全文检索,可以使用sphinx的中文版(coreseek)
        CREATE TABLE articles (
                            id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
                            title VARCHAR(200),    
                            body TEXT,
                            FULLTEXT (title,body)
                    )engine=MyISAM;
        添加数据
                        INSERT INTO articles (title,body) VALUES    ('MySQL Tutorial','DBMS stands for DataBase ...'),('How To Use MySQL Well','After you went through a ...'),('Optimizing MySQL','In this tutorial we will show ...'),('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),('MySQL vs. YourSQL','In the following database comparison ...'),('MySQL Security','When configured properly, MySQL ...');
        查询有没有 database 数据:
                如果使用如下查询方式,虽然查询出数据,但是没有使用到全文索引    
                mysql> select * from articles where body like '%database%';

        5、查询索引

                方法1show keys from 表名
                方法2: show index from 表名;
                方法3desc 表名; -- 但是信息比较简略

        6、删除索引

            方法1: 删除主键: alter table 表名 drop primary;
            方法2: 其他索引的删除:alter table 表名 drop index 索引名;--索引名就是show keys from 表名中的 Key_name 字段
                            mysql> alter table user10 drop index idx_name;

            方法3 drop index 索引名 on 表名 

                          <mysql> drop index name on user8;

        7、索引的原则         

                比较平凡作为查询条件的字段应该创建索引
                唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
                    select * from EMP where sex=' ';
                更新非常频繁的字段不适合作创建索引
                不会出现在
where 子句中的字段不该创建索引
事物
             事务就是一组 dml 语句组成,这些语句在逻辑上存在相关性,这一组 dml 语句要么全部成功,要么全部失败,是一
个整体。
MySQL 提供一种机制,保证我们达到这样的效果。事务还规定不同的客户端看到的数据时不相同的。
事务理论的深度理解参见推荐书籍:《数据库系统概念》的第
14 章。
        
             银行转账的例子更需要考虑事务的问题。
                    create table account(
                                        id int primary key,
                                        name varchar(50) not null default '',
                                        balance decimal(10, 2) not null default 0.0    
                    );

             基本使用:
                    开始一个事务            
start transaction;
                    做一个保存点             savepoint 保存点名;
                    进行各种操作
                     如果需要,可以回到保存点        
rollback to 保存点名
             示例:
                    mysql> start transaction; -- 开启事务
                            Query OK, 0 rows affected (0.00 sec)
                    mysql> savepoint aa; --
设置保存点 aa
                            Query OK, 0 rows affected (0.00 sec)
                    mysql> insert into account values(1, '
张三 ', 10); -- 添加一条记录
                            Query OK, 1 row affected (0.00 sec)
                    mysql> savepoint bb; --
设置保存点 bb
                            Query OK, 0 rows affected (0.00 sec)
                    mysql> insert into account values(2, '
李四 ', 10000); -- 再添加一条记录
                            Query OK, 1 row affected (0.00 sec)
                    mysql> select * from account; --
两条记录都在了
                     mysql> rollback to bb; -- 发现后来添加这一条记录是误操作。所以回滚到 bb 状态
                            Query OK, 0 rows affected (0.01 sec)
                    mysql> select * from account; --
第二条记录没有了

                 事务操作注意点:
                    (1).如果没有设置保存点,也可以回滚,只能回滚到事务的开始。直接使用 rollback( 前提是还没有提交 )
                    (2). 如果一个事务被提交了,则不可以回退( commit
                    (3). 可以选择回退到哪个保存点
                    (4).InnoDB 支持事务, MyISAM 不支持事务。
                    (5).开始事务可以使
start transaction 也可以是 set autocommit = 0;

            1、 事务的隔离级别
                     MySQL 表被多个线程或者客户端开启各自事务操作数据库中的数据时, MySQL 提供了一种机制,可以让不同的
事务在操作数据时,具有隔离性。从而保证数据的一致性。如果不考虑隔离性,可能会引发一下问题:
                    脏读
                    不可重复读
                    幻读
                事务的隔离级别有几种:

          

             2、设置事务的隔离级别

                    语法:    set session transaction isolation level read uncommitted;
                    查看当前的隔离级别:    mysql> select @@tx_isolation;
                    脏读:一个客户端(事务)会读取到另外一个客户端(事务)没有提交的修改数据。
                    不可重复读:同一个查询在同一个事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果
集,此时发生不可重复读。
                    幻读:同一个查询在同一个事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发

生幻读。可串行化,如下图所示:

                    注意: mysql默认的隔离级别是可重复读,一般情况下不要修改
            3、事务的ACID特性
                    (1). 原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
                    (2). 一致性(Consistency):事务必须使数据库从一个一致性状态变到另外一个一致性状态。
                    (3). 隔离性(Isolation):事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据
所干扰,多个并发事务之间要相互隔离。
                    (4). 持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中的数据的修改就是永久性的,接下来即使数据库发生故障也

不应该对其有任何影响 

视图

       视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。视图的数据变
化会影响到基表,基表的数据变化也会影响到视图

        1、创建视图        create view 视图名 as select语句;
                示例:mysql> create view v_ename_dname as
                                  -> select ename, dname
                                  -> from EMP, DEPT where EMP.deptno=DEPT.deptno;
                           mysql> select * from v_ename_dname;

        2、修改了视图,对基表数据有影响
                mysql> update v_ename_dname set dname='sales' where ename='CLARK';
                mysql> select * from EMP where ename='CLARK';

        3、修改了基表,对视图有影响
                mysql> update EMP set deptno=20 where ename='JAMES'; -- 修改基表
        4、删除视图    drop view 视图名;
        5、视图和表的区别
                (1). 表要占用磁盘空间,视图不需要
                (2). 视图不能添加索引
                (3). 使用视图可以简化查询
                (4). 视图可以提高安全性

猜你喜欢

转载自blog.csdn.net/qq_35396127/article/details/80470333