前言:
目前看官们对“mysql调用外部程序”都比较看重,咱们都需要剖析一些“mysql调用外部程序”的相关内容。那么小编同时在网络上收集了一些有关“mysql调用外部程序””的相关内容,希望同学们能喜欢,大家一起来了解一下吧!Mysql基础入门一、Mysql介绍1.1基础概念
数据库
数据库就是[存储数据的仓库],其本质是一个[文件系统],数据按照特定的格式将数据存储起来,用户可以通过SQL对数据库中的数据进行增加,修改,删除及查询操作。
关系型数据库
数据库中的[记录是有行有列的数据库]就是关系型数据库,与之相反的就是NoSQL数据库了。
数据库和表
数据库管理系统(DataBase Management System,DBMS):指一种[操作和管理数据库]的大型软件,用于建立、使用和维护数据库,对数据库进行统一管理和控制,以保证数据库的安全性和完整性。用户通过数据库管理系统访问数据库中表内的数据。(记录)
常见的数据库管理系统
- MYSQL :开源免费的数据库,小型的数据库.已经被Oracle收购了。MySQL5.5版本之后都是由Oracle发布的版本。- Oracle :收费的大型数据库,Oracle公司的产品。Oracle收购SUN公司,收购MYSQL。- DB2 :IBM公司的数据库产品,收费的。常应用在银行系统中。在中国的互联网公司,要求去IOE(IBM小型机、Oracle数据库、EMC存储设备)- SQLServer:MicroSoft 公司收费的中型的数据库。C#、.net等语言常使用。- SyBase :已经淡出历史舞台。提供了一个非常专业数据建模的工具PowerDesigner。- SQLite : 嵌入式的小型数据库,应用在手机端。
MySQL
MySQL 是最流行的【关系型数据库管理系统】,在WEB应用方面 MySQL是最好的RDBMS应用软件之一。
MySQL发展历程
- MySQL的历史可以追溯到1979年,一个名为Monty Widenius的程序员在为TcX的小公司打工,并且用BASIC设计了一个报表工具,使其可以在4MHz主频和16KB内存的计算机上运行。当时,这只是一个很底层的且仅面向报表的存储引擎,名叫Unireg。- 1990年,TcX公司的客户中开始有人要求为他的API提供SQL支持。Monty直接借助于mSQL的代码,将它集成到自己的存储引擎中。令人失望的是,效果并不太令人满意,决心自己重写一个SQL支持。- 1996年,MySQL 1.0发布,它只面向一小拨人,相当于内部发布。- 到了1996年10月,MySQL 3.11.1发布(MySQL没有2.x版本),最开始只提供Solaris下的二进制版本。一个月后,Linux版本出现了。在接下来的两年里,MySQL被依次移植到各个平台。- 【1999~2000年】,【MySQL AB】公司在瑞典成立。Monty雇了几个人与Sleepycat合作,开发出了【Berkeley DB引擎】, 由于BDB支持事务处理,因此MySQL从此开始支持事务处理了。- 2000,MySQL不仅公布自己的源代码,并采用GPL(GNU General Public License)许可协议,正式进入开源世界。同年4月,MySQL对旧的存储引擎ISAM进行了整理,将其命名为MyISAM。- 2001年,集成Heikki Tuuri的存储引擎【InnoDB】,这个引擎不仅能【支持事务处理,并且支持行级锁】。后来该引擎被证明是最为成功的MySQL事务存储引擎。【MySQL与InnoDB的正式结合版本是4.0】- 2003年12月,【MySQL 5.0】版本发布,提供了视图、存储过程等功能。- 【2008年1月】,【MySQL AB公司被Sun公司以10亿美金收购】,MySQL数据库进入Sun时代。在Sun时代,Sun公司对其进行了大量的推广、优化、Bug修复等工作。- 2008年11月,MySQL 5.1发布,它提供了分区、事件管理,以及基于行的复制和基于磁盘的NDB集群系统,同时修复了大量的Bug。- 【2009年4月】,Oracle公司以74亿美元收购Sun公司,自此MySQL数据库进入Oracle时代,而其第三方的存储引擎InnoDB早在2005年就被Oracle公司收购。- 2010年12月,【MySQL 5.5发布】,其主要新特性包括半同步的复制及对SIGNAL/RESIGNAL的异常处理功能的支持,【最重要的是InnoDB存储引擎终于变为当前MySQL的默认存储引擎】。MySQL 5.5不是时隔两年后的一次简单的版本更新,而是加强了MySQL各个方面在企业级的特性。Oracle公司同时也承诺MySQL 5.5和未来版本仍是采用GPL授权的开源产品。
SQL
【SQL是Structured Query Language的缩写】,它的前身是著名的关系数据库原型系统System R所采用的SEQUEL语言。作为一种访问【关系型数据库的标准语言】,SQL自问世以来得到了广泛的应用,不仅是著名的大型商用数据库产品Oracle、DB2、Sybase、SQL Server支持它,很多开源的数据库产品如PostgreSQL、MySQL也支持它,甚至一些小型的产品如Access也支持SQL。近些年蓬勃发展的NoSQL系统最初是宣称不再需要SQL的,后来也不得不修正为Not Only SQL,来拥抱SQL。蓝色巨人IBM对关系数据库以及SQL语言的形成和规范化产生了重大的影响,第一个版本的SQL标准SQL86就是基于System R的手册而来的。Oracle在1979年率先推出了支持SQL的商用产品。随着数据库技术和应用的发展,为不同RDBMS提供一致的语言成了一种现实需要。对SQL标准影响最大的机构自然是那些著名的数据库产商,而具体的制订者则是一些非营利机构,例如【国际标准化组织ISO、美国国家标准委员会ANSI】等。各国通常会按照 ISO标准和ANSI标准(这两个机构的很多标准是差不多等同的)制定自己的国家标准。中国是ISO标准委员会的成员国,也经常翻译一些国际标准对应的中文版。标准为了避免采用具体产品的术语,往往会抽象出很多名词,从而增加了阅读和理解的难度,翻译成中文之后更容易词不达意。对于数据库系统实现者和用户而言,很多时候还不如直接读英文版本为好。虽然正式的标准不像RFC那样可以从网络上免费获得,标准草案还是比较容易找到的(例如:)。待批准的标准草案和最终的标准也没有什么实质上的区别,能够满足日常工作的需要。下面是SQL发展的简要历史:1986年,ANSI X3.135-1986,ISO/IEC 9075:1986,SQL-861989年,ANSI X3.135-1989,ISO/IEC 9075:1989,SQL-891992年,ANSI X3.135-1992,ISO/IEC 9075:1992,SQL-92(SQL2)1999年,ISO/IEC 9075:1999,SQL:1999(SQL3)2003年,ISO/IEC 9075:2003,SQL:20032008年,ISO/IEC 9075:2008,SQL:20082011年,ISO/IEC 9075:2011,SQL:2011如果要了解标准的内容,比较推荐的方法是【泛读SQL92】(因为它涉及了SQL最基础和最核心的一些内容),然后增量式的阅读其他标准。
不只是mysql还有其他数据库,在SQL92或者SQL99这些国际SQL标准基础之上,它们还扩展了自己的一些SQL语句,比如MySQL中的limit关键字
SQL语言分类
- 数据定义语言:简称【DDL】(Data Definition Language),用来定义数据库对象:数据库,表,列等。关键字:create,alter,drop等- 数据操作语言:简称【DML】(Data Manipulation Language),用来对数据库中表的记录进行更新。关键字:insert,delete,update等- 数据控制语言:简称【DCL】(Data Control Language),用来定义数据库的访问权限和安全级别,及创建用户;关键字:grant等- 数据查询语言:简称【DQL】(Data Query Language),用来查询数据库中表的记录。关键字:select,from,where等
1.2MySQL安装
操作系统:CentOS 7
MySQL:5.6
#查看是否安装rpm -qa|grep mysqlyum repolist all | grep mysql
1、卸载MySQL
yum remove -y mysql mysql-libs mysql-common #卸载mysqlrm -rf /var/lib/mysql #删除mysql下的数据文件rm /etc/my.cnf #删除mysql配置文件yum remove -y mysql-community-release-el6-5.noarch #删除组件
2、安装MySQL5.6
#下载rpm文件wget 执行rpm源文件rpm -ivh mysql-community-release-el6-5.noarch.rpm#执行安装文件yum install mysql-community-server
启动MySQL
systemctl start mysqld
设置root用户密码
例如:为 root 账号设置密码为 root :/usr/bin/mysqladmin -u root password 'root' #没有密码 有原来的密码则加/usr/bin/mysqladmin -u root -p '123' password 'root'
登录MySQL
mysql -uroot -proot-u:指定数据库用户名-p:指定数据库密码,记住-u和登录密码之间没有空格
配置MySQL
vim /etc/my.cnf[mysqld]# MySQL设置大小写不敏感:默认:区分表名的大小写,不区分列名的大小写# 0:大小写敏感 1:大小写不敏感lower_case_table_names=1# 默认字符集character-set-server=utf8
MySQL远程连接授权
授权命令grant 权限 on 数据库对象 to 用户GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;FLUSH PRIVILEGES;--刷新权限说明ALL PRIVILEGES :表示授予所有的权限,此处可以指定具体的授权权限。*.* :表示所有库中的所有表'root'@'%' : myuser是数据库的用户名,%表示是任意ip地址,可以指定具体ip地址。IDENTIFIED BY 'mypassword' :mypassword是数据库的密码。
授权命令grant 权限 on 数据库对象 to 用户GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;FLUSH PRIVILEGES;--刷新权限说明ALL PRIVILEGES :表示授予所有的权限,此处可以指定具体的授权权限。*.* :表示所有库中的所有表'root'@'%' : myuser是数据库的用户名,%表示是任意ip地址,可以指定具体ip地址。IDENTIFIED BY 'mypassword' :mypassword是数据库的密码。授权命令grant 权限 on 数据库对象 to 用户GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;FLUSH PRIVILEGES;--刷新权限说明ALL PRIVILEGES :表示授予所有的权限,此处可以指定具体的授权权限。*.* :表示所有库中的所有表'root'@'%' : myuser是数据库的用户名,%表示是任意ip地址,可以指定具体ip地址。IDENTIFIED BY 'mypassword' :mypassword是数据库的密码。授权命令grant 权限 on 数据库对象 to 用户GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;FLUSH PRIVILEGES;--刷新权限说明ALL PRIVILEGES :表示授予所有的权限,此处可以指定具体的授权权限。*.* :表示所有库中的所有表'root'@'%' : myuser是数据库的用户名,%表示是任意ip地址,可以指定具体ip地址。IDENTIFIED BY 'mypassword' :mypassword是数据库的密码。授权命令grant 权限 on 数据库对象 to 用户GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;FLUSH PRIVILEGES;--刷新权限说明ALL PRIVILEGES :表示授予所有的权限,此处可以指定具体的授权权限。*.* :表示所有库中的所有表'root'@'%' : myuser是数据库的用户名,%表示是任意ip地址,可以指定具体ip地址。IDENTIFIED BY 'mypassword' :mypassword是数据库的密码。
关闭linux的防火墙
systemctl stop firewalld(默认)systemctl disable firewalld.service(设置开启不启动)
3、MySQL5.7安装
安装方式:通过rmp离线包的方式安装。
卸载Linux自带mariadb
rpm -qa | grep mariabdrpm -e mariadb… --nodepsrpm -qa | grep mariabd
解压rpm包
tar -xvf 包名;
安装
#安装公共包rpm -ivh mysql-community-common-5.7.28-1.el7.x86_64.rpmrpm -ivh mysql-community-libs-5.7.28-1.el7.x86_64.rpmrpm -ivh mysql-community-libs-compat-5.7.28-1.el7.x86_64.rpm#安装服务端和客户端rpm -ivh mysql-community-client-5.7.28-1.el7.x86_64.rpmrpm -ivh mysql-community-server-5.7.28-1.el7.x86_64.rpm#安装工具包rpm -ivh mysql-community-devel-5.7.28-1.el7.x86_64.rpm#初始化mysql 并创建一个user的用户mysqld --initialize --user=mysql
登录设置密码
#启动mysqlsystemctl start mysqld#查看默认密码cat /var/log/mysqld.log | grep password #登录mysql -uroot -p9Nurpw%Ff/w##修改密码set password=password('root');
二、Mysql基本语法2.1 DDL语句1、数据库操作
创建数据库
create database 数据库名;create database 数据库名 character set 字符集;
查看数据库
show databases;show create database 数据库名;
删除数据库慎用
drop database 数据库名称;
其他数据库操作命令
切换数据库use 数据库名;查看正在使用的数据库select database();
2、表操作
常用的类型
数字型:int浮点型:double字符型:varchar(可变长字符串)日期类型:date(只有年月日,没有时分秒) datetime(年月日,时分秒)boolean类型:不支持,一般使用tinyint替代(值为0和1)
创建表
create table 表名( 字段名 类型(长度) 约束, 字段名 类型(长度) 约束);
单表约束:
- 主键约束:primary key- 唯一约束:unique- 非空约束:not null主键约束 = 唯一约束 + 非空约束
查看表
show tables;desc 表名;【查看表结构】
修改表
alter table 表名 add 列名 类型(长度) 约束; --修改表添加列.alter table 表名 modify 列名 类型(长度) 约束; --修改表修改列的类型长度及约束.alter table 表名 change 旧列名 新列名 类型(长度) 约束; --修改表修改列名.alter table 表名 drop 列名; --修改表删除列.rename table 表名 to 新表名; --修改表名alter table 表名 character set 字符集; --修改表的字符集
2.2DML语句1、Insert语句
insert into 表 (列名1,列名2,列名3..) values (值1,值2,值3..); -- 向表中插入某些列insert into 表 values (值1,值2,值3..); --向表中插入所有列insert into 表 (列名1,列名2,列名3..) values select (列名1,列名2,列名3..) from 表insert into 表 values select * from 表
注意:
1. 列名数与values后面的值的个数相等
2. 列的顺序与插入的值得顺序一致
3. 列名的类型与插入的值要一致.
4. 插入值得时候不能超过最大长度.
5. 值如果是字符串或者日期需要加引号’’ (一般是单引号)
例子:
INSERT INTO sort(sid,sname) VALUES('s001', '电器');INSERT INTO sort(sid,sname) VALUES('s002', '服饰');INSERT INTO sort VALUES('s003', '化妆品');INSERT INTO sort VALUES('s004','书籍');
2、update
update 表名 set 字段名=值,字段名=值;update 表名 set 字段名=值,字段名=值 where 条件;
注意:
1. 列名的类型与修改的值要一致.
2. 修改值得时候不能超过最大长度.
3. 值如果是字符串或者日期需要加’’.
3、delete
delete from 表名 [where 条件];
面试题:
删除表中所有记录使用【delete from 表名】,还是用【truncate table 表名】?删除方式:- delete :一条一条删除,不清空auto_increment记录数。- truncate :直接将表删除,重新建表,auto_increment将置为零,从新开始。
2.3DQL语句1、准备
案例演示:#商品表CREATE TABLE product (pid INT PRIMARY KEY AUTO_INCREMENT, # 自增加 AUTO_INCREMENTpname VARCHAR(20),#商品名称price DOUBLE, #商品价格pdate DATE, # 日期cid int #分类ID);#目录表create table category( id INT PRIMARY KEY , cname varchar(100));INSERT INTO product VALUES(NULL,'泰国大榴莲', 98, NULL, 1);INSERT INTO product VALUES(NULL,'泰国大枣', 38, NULL, 1);INSERT INTO product VALUES(NULL,'新疆切糕', 68, NULL, 2);INSERT INTO product VALUES(NULL,'十三香', 10, NULL, 2);INSERT INTO product VALUES(NULL,'泰国大枣', 20, NULL, 2);insert into product values(null,'泰国大枣',98,null,20); #没有对应insert into product values(null,'iPhone手机',800,null,30);#没有对应INSERT INTO category VALUES(1,'国外食品');INSERT INTO category VALUES(2,'国内食品');INSERT INTO category VALUES(3,'国内服装'); #没有对应
2、完整DQL语法顺序
SELECT DISTINCT < select_list >FROM < left_table > < join_type >JOIN < right_table > ON < join_condition >WHERE < where_condition >GROUP BY < group_by_list >HAVING < having_condition >ORDER BY < order_by_condition >LIMIT < limit_number >
3、简单查询
查询所有的商品
select * from product;
查询商品名称和商品价格
select pname,price from product;
别名查询,使用的as关键字,as可以省略的
表别名:
select * from product as p;
列别名:
select pname as pn from product;
去掉重复值.
select distinct price from product;
查询结果是表达式(运算查询):将所有商品的价格+10元进行显示.
select pname,price+10 from product;
4、条件查询
查询商品名称为十三香的商品所有信息:
select * from product where pname = '十三香';
查询商品价格>60元的所有的商品信息:
select * from product where price > 60;
where后的条件写法:
> ,<,=,>=,<=,<>like 使用占位符 _ 和 % _代表一个字符 %代表任意个字符. select * from product where pname like '%新%';in在某个范围中获得值(exists). select * from product where pid in (2,5,8);
5、排序
查询所有的商品,按价格进行排序.(asc-升序,desc-降序)
select * from product order by price;
查询名称有新的商品的信息并且按价格降序排序.
select * from product where pname like '%新%' order by price desc;
6、聚合函数(组函数)
特点:只对单列进行操作
常用的聚合函数:
sum():求某一列的和avg():求某一列的平均值max():求某一列的最大值min():求某一列的最小值count():求某一列的元素个数
获得所有商品的价格的总和:
select sum(price) from product;
获得所有商品的平均价格:
select avg(price) from product;
获得所有商品的个数:
select count(*) from product;
6、分组
根据cno字段分组,分组后统计商品的个数.
select cid,count(*) from product group by cid;
根据cno分组,分组统计每组商品的平均价格,并且平均价格> 60;
select cid,avg(price) from product group by cid having avg(price)>60;
注意事项:
1. select语句中的列(非聚合函数列),必须出现在group by子句中2. group by子句中的列,不一定要出现在select语句中3. 聚合函数只能出现select语句中或者having语句中,一定不能出现在where语句中。
7、分页查询
lIMIT 关键字不是 SQL92 标准提出的关键字,它是 MySQL 独有的语法。
通过 limit 关键字, MySQL 实现了物理分页。
分页分为逻辑分页和物理分页:
逻辑分页:将数据库中的数据查询到内存之后再进行分页。物理分页:通过LIMIT关键字,直接在数据库中进行分页,最终返回的数据,只是分页后的数据。
格式:
ELECT * FROM table LIMIT [offset,] rows
案例:分页查询商品表,每页3条记录,查第一页
select * from product limit 0,3
8、子查询
子查询允许把一个查询嵌套在另一个查询当中。子查询,又叫内部查询,相对于内部查询,包含内部查询的就称为外部查询。子查询可以包含普通select可以包括的任何子句,比如:distinct、 group by、order by、limit、
join和union等;但是对应的外部查询必须是以下语句之一:select、insert、update、delete。
子查询位置:select中、from 后、where 中.
案例:查询“化妆品”分类下的商品信息
select * from product where type = (select type from table2 )
9、其他查询语句
union 集合的并集(不包含重复记录)
unionall 集合的并集(包含重复记录)
三、SQL解析3.1SQL解析顺序
SELECT DISTINCT < select_list >FROM < left_table > < join_type >JOIN < right_table > ON < join_condition >WHERE < where_condition >GROUP BY < group_by_list >HAVING < having_condition >ORDER BY < order_by_condition >LIMIT < limit_number >
解析顺序
-- 行过滤1 FROM <left_table>2 ON <join_condition>3 <join_type> JOIN <right_table> 第二步和第三步会循环执行4 WHERE <where_condition> 第四步会循环执行,多个条件的执行顺序是从左往右的。5 GROUP BY <group_by_list>6 HAVING <having_condition>--列过滤7 SELECT 分组之后才会执行SELECT8 DISTINCT <select_list>--排序9 ORDER BY <order_by_condition>-- MySQL附加10 LIMIT <limit_number> 前9步都是SQL92标准语法。limit是MySQL的独有语法。
虽然自己没想到是这样的,不过一看还是很自然和谐的,从哪里获取,不断的过滤条件,要选择一样或不一样的,排好序,那才知道要取前几条呢。既然如此了,那就让我们根据案例一步步来看看其中的细节吧。
3.2SQL解析详细步骤1、FROM
对FROM的左边的表和右边的表计算 笛卡尔积(CROSS JOIN) 。产生 虚表VT1
mysql> select * from product,category;+-----+-----------------+-------+-------+------+----+--------------+| pid | pname | price | pdate | cid | id | cname |+-----+-----------------+-------+-------+------+----+--------------+| 1 | 泰国大榴莲 | 98 | NULL | 1 | 1 | 国外食品 || 1 | 泰国大榴莲 | 98 | NULL | 1 | 2 | 国内食品 || 1 | 泰国大榴莲 | 98 | NULL | 1 | 3 | 国内服装 || 2 | 泰国大枣 | 38 | NULL | 1 | 1 | 国外食品 || 2 | 泰国大枣 | 38 | NULL | 1 | 2 | 国内食品 || 2 | 泰国大枣 | 38 | NULL | 1 | 3 | 国内服装 || 3 | 新疆切糕 | 68 | NULL | 2 | 1 | 国外食品 || 3 | 新疆切糕 | 68 | NULL | 2 | 2 | 国内食品 || 3 | 新疆切糕 | 68 | NULL | 2 | 3 | 国内服装 || 4 | 十三香 | 10 | NULL | 2 | 1 | 国外食品 || 4 | 十三香 | 10 | NULL | 2 | 2 | 国内食品 || 4 | 十三香 | 10 | NULL | 2 | 3 | 国内服装 || 5 | 泰国大枣 | 20 | NULL | 2 | 1 | 国外食品 || 5 | 泰国大枣 | 20 | NULL | 2 | 2 | 国内食品 || 5 | 泰国大枣 | 20 | NULL | 2 | 3 | 国内服装 || 6 | 泰国大枣 | 98 | NULL | 20 | 1 | 国外食品 || 6 | 泰国大枣 | 98 | NULL | 20 | 2 | 国内食品 || 6 | 泰国大枣 | 98 | NULL | 20 | 3 | 国内服装 || 7 | iPhone手机 | 800 | NULL | 30 | 1 | 国外食品 || 7 | iPhone手机 | 800 | NULL | 30 | 2 | 国内食品 || 7 | iPhone手机 | 800 | NULL | 30 | 3 | 国内服装 |+-----+-----------------+-------+-------+------+----+--------------+21 rows in set (0.00 sec)
2、ON过滤
对虚表VT1 进行ON筛选,只有那些符合的行才会被记录在虚表VT2中。
注意:这里因为语法限制,使用了'WHERE'代替,从中读者也可以感受到两者之间微妙的关系;
mysql> select * from product a , category b where a.cid=b.id;+-----+-----------------+-------+-------+------+----+--------------+| pid | pname | price | pdate | cid | id | cname |+-----+-----------------+-------+-------+------+----+--------------+| 1 | 泰国大榴莲 | 98 | NULL | 1 | 1 | 国外食品 || 2 | 泰国大枣 | 38 | NULL | 1 | 1 | 国外食品 || 3 | 新疆切糕 | 68 | NULL | 2 | 2 | 国内食品 || 4 | 十三香 | 10 | NULL | 2 | 2 | 国内食品 || 5 | 泰国大枣 | 20 | NULL | 2 | 2 | 国内食品 |+-----+-----------------+-------+-------+------+----+--------------+5 rows in set (0.00 sec)
3、OUTER JOIN添加外部列
如果指定了 OUTER JOIN(比如left join、 right join) ,那么 保留表中未匹配的行 就会作为外部行添加 到 虚拟表VT2 中,产生 虚拟表VT3 。
如果FROM子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为止。
mysql> select * from product a left outer join category b on a.cid=b.id; # 以左表数据为准+-----+-----------------+-------+-------+------+------+--------------+| pid | pname | price | pdate | cid | id | cname |+-----+-----------------+-------+-------+------+------+--------------+| 1 | 泰国大榴莲 | 98 | NULL | 1 | 1 | 国外食品 || 2 | 泰国大枣 | 38 | NULL | 1 | 1 | 国外食品 || 3 | 新疆切糕 | 68 | NULL | 2 | 2 | 国内食品 || 4 | 十三香 | 10 | NULL | 2 | 2 | 国内食品 || 5 | 泰国大枣 | 20 | NULL | 2 | 2 | 国内食品 || 6 | 泰国大枣 | 98 | NULL | 20 | NULL | NULL || 7 | iPhone手机 | 800 | NULL | 30 | NULL | NULL |+-----+-----------------+-------+-------+------+------+--------------+7 rows in set (0.00 sec)mysql> select * from product a right outer join category b on a.cid=b.id; #以右表数据为准+------+-----------------+-------+-------+------+----+--------------+| pid | pname | price | pdate | cid | id | cname |+------+-----------------+-------+-------+------+----+--------------+| 1 | 泰国大榴莲 | 98 | NULL | 1 | 1 | 国外食品 || 2 | 泰国大枣 | 38 | NULL | 1 | 1 | 国外食品 || 3 | 新疆切糕 | 68 | NULL | 2 | 2 | 国内食品 || 4 | 十三香 | 10 | NULL | 2 | 2 | 国内食品 || 5 | 泰国大枣 | 20 | NULL | 2 | 2 | 国内食品 || NULL | NULL | NULL | NULL | NULL | 3 | 国内服装 |+------+-----------------+-------+-------+------+----+--------------+6 rows in set (0.00 sec)
4、WHERE
对虚拟表VT3 进行WHERE条件过滤。只有符合的记录才会被插入到 虚拟表VT4 中。
注意:
此时因为分组,不能使用聚合运算;也不能使用SELECT中创建的别名;
与ON的区别:
如果有外部列,ON针对过滤的是关联表,主表(保留表)会返回所有的列;
如果没有添加外部列,两者的效果是一样的;
应用:
对主表的过滤应该放在WHERE;
对于关联表,先条件查询后连接则用ON,先连接后条件查询则用WHERE;
mysql> select * from product a left outer join category b on a.cid=b.id wherea.pname='泰国大枣';+-----+--------------+-------+-------+------+------+--------------+| pid | pname | price | pdate | cid | id | cname |+-----+--------------+-------+-------+------+------+--------------+| 2 | 泰国大枣 | 38 | NULL | 1 | 1 | 国外食品 || 5 | 泰国大枣 | 20 | NULL | 2 | 2 | 国内食品 || 6 | 泰国大枣 | 98 | NULL | 20 | NULL | NULL |+-----+--------------+-------+-------+------+------+--------------+3 rows in set (0.00 sec)
5、GROUP BY
根据group by子句中的列,对VT4中的记录进行分组操作,产生 虚拟表VT5 。
注意:
其后处理过程的语句,如SELECT,HAVING,所用到的列必须包含在GROUP BY中。对于没有出现的,得用聚合函数;
原因:
GROUP BY改变了对表的引用,将其转换为新的引用方式,能够对其进行下一级逻辑操作的列会减少;
我的理解是:
根据分组字段,将具有相同分组字段的记录归并成一条记录,因为每一个分组只能返回一条记录,除非是被过滤掉了,而不在分组字段里面的字段可能会有多个值,多个值是无法放进一条记录的,所以必须通过聚合函数将这些具有多值的列转换成单值;
mysql> select * from product a left outer join category b on a.cid=b.id wherea.pname='泰国大枣' group by a.price;+-----+--------------+-------+-------+------+------+--------------+| pid | pname | price | pdate | cid | id | cname |+-----+--------------+-------+-------+------+------+--------------+| 5 | 泰国大枣 | 20 | NULL | 2 | 2 | 国内食品 || 2 | 泰国大枣 | 38 | NULL | 1 | 1 | 国外食品 || 6 | 泰国大枣 | 98 | NULL | 20 | NULL | NULL |+-----+--------------+-------+-------+------+------+--------------+3 rows in set (0.01 sec)
6、HAVING
对 虚拟表VT5 应用having过滤,只有符合的记录才会被 插入到 虚拟表VT6 中。
mysql> select * from product a left outer join category b on a.cid=b.id wherea.pname='泰国大枣' group by a.price having b.id <=2;+-----+--------------+-------+-------+------+------+--------------+| pid | pname | price | pdate | cid | id | cname |+-----+--------------+-------+-------+------+------+--------------+| 5 | 泰国大枣 | 20 | NULL | 2 | 2 | 国内食品 || 2 | 泰国大枣 | 38 | NULL | 1 | 1 | 国外食品 |+-----+--------------+-------+-------+------+------+--------------+2 rows in set (0.00 sec)
7、SELECT
这个子句对SELECT子句中的元素进行处理,生成VT5表。
(5-J1)计算表达式 计算SELECT 子句中的表达式,生成VT5-J1
8、DISTINCT
寻找VT5-1中的重复列,并删掉,生成VT5-J2
如果在查询中指定了DISTINCT子句,则会创建一张内存临时表(如果内存放不下,就需要存放在硬盘
了)。这张临时表的表结构和上一步产生的虚拟表VT5是一样的,不同的是对进行DISTINCT操作的列增
加了一个唯一索引,以此来除重复数据。
mysql> select distinct a.pname from product a left outer join category b ona.cid=b.id where a.pname='泰国大枣' group by a.price ;+--------------+| pname |+--------------+| 泰国大枣 |+--------------+1 row in set (0.00 sec)
9、ORDER BY
从 VT5-J2 中的表中,根据ORDER BY 子句的条件对结果进行排序,生成VT6表。
注意:
唯一可使用SELECT中别名的地方;
mysql> select * from product a left outer join category b on a.cid=b.id wherea.pname='泰国大枣' group by a.price having b.id <=2 order by b.id;+-----+--------------+-------+-------+------+------+--------------+| pid | pname | price | pdate | cid | id | cname |+-----+--------------+-------+-------+------+------+--------------+| 2 | 泰国大枣 | 38 | NULL | 1 | 1 | 国外食品 || 5 | 泰国大枣 | 20 | NULL | 2 | 2 | 国内食品 |+-----+--------------+-------+-------+------+------+--------------+2 rows in set (0.00 sec)
10、LIMIT
LIMIT子句从上一步得到的 VT6虚拟表 中选出从指定位置开始的指定行数据。
注意:
offset 和 rows 的正负带来的影响;
当偏移量很大时效率是很低的,可以这么做:
采用子查询的方式优化 ,在子查询里先从索引获取到最大id,然后倒序排,再取N行结果集
采用INNER JOIN优化 ,JOIN子句里也优先从索引获取ID列表,然后直接关联查询获得最终结果
mysql> select * from product a left outer join category b on a.cid=b.id wherea.pname='泰国大枣' group by a.price having b.id <=2 order by b.id limit 1; +-----+--------------+-------+-------+------+------+--------------+| pid | pname | price | pdate | cid | id | cname |+-----+--------------+-------+-------+------+------+--------------+| 2 | 泰国大枣 | 38 | NULL | 1 | 1 | 国外食品 |+-----+--------------+-------+-------+------+------+--------------+1 row in set (0.00 sec)
3.3SQL解析顺序总结
1、流程分析:
1. FROM(将最近的两张表,进行笛卡尔积)---VT1
2. ON(将VT1按照它的条件进行过滤)---VT2
3. LEFT JOIN(保留左表的记录)---VT3
4. WHERE(过滤VT3中的记录)--VT4…VTn
5. GROUP BY(对VT4的记录进行分组)---VT5
6. HAVING(对VT5中的记录进行过滤)---VT6
7. SELECT(对VT6中的记录,选取指定的列)--VT7
8. ORDER BY(对VT7的记录进行排序)--VT8
9. LIMIT(对排序之后的值进行分页)--MySQL特有的语法
2、流程说明:单表查询:根据 WHERE 条件过滤表中的记录,形成中间表(这个中间表对用户是不可见的);然后根据 SELECT 的选择列选择相应的列进行返回最终结果。两表连接查询:对两表求积(笛卡尔积)并用 ON 条件和连接连接类型进行过滤形成中间表;然后根据WHERE条件过滤中间表的记录,并根据 SELECT 指定的列返回查询结果。【笛卡尔积:行相乘、列相加。】多表连接查询:先对第一个和第二个表按照两表连接做查询,然后用查询结果和第三个表做连接查询,以此类推,直到所有的表都连接上为止,最终形成一个中间的结果表,然后根据WHERE条件过滤中间表的记录,并根据SELECT指定的列返回查询结果。3、WHERE条件解析顺序
1. MySQL :从左往右去执行 WHERE 条件的。
2. Oracle :从右往左去执行 WHERE 条件的。
写WHERE条件的时候,优先级高的部分要去编写过滤力度最大的条件语句。
标签: #mysql调用外部程序