1. SQL简介

SQL介绍

Structured Query Language简称SQL,是一种操作数据库的语言。它包括数据库创建,删除,获取行,修改行等。SQL是结构化查询语言,它是一种用于存储,处理和检索关系数据库中存储的数据的计算机语言。
SQL是关系数据库系统的标准语言。所有关系数据库管理系统(RDMS),例如MySQL,MS Access,Oracle,Sybase,Informix,Postgres和SQL Server,都使用SQL作为其标准数据库语言。

SQL组件

  • 当RDBMS执行SQL命令时,系统会找出执行请求的最佳方法,而SQL引擎会确定如何解释该任务。在该过程中,包括各种组件。
  • 这些组件可以是优化引擎,查询引擎,查询调度程序,经典查询引擎等。
  • 所有非SQL查询都由经典查询引擎处理,但SQL查询引擎不会处理逻辑文件。
    以下是显示SQL体系结构的简单图:

SQL历史

  • 1970年,SQL由IBM的Donald D. Chamberlin和Raymond F. Boyce开发。
  • 1974年,开发版本最初被称为SEQUEL(结构化英语查询语言)。
  • 1979年,关系软件发布了第一个叫做System / R的商业产品。
  • 由于商标冲突问题,SEQUEL首字母缩略词后来更改为SQL。
  • 后来IBM基于System / R的原型开始在SQL上开发商业产品。
  • 第一个关系数据库由RelationalSoftware发布,后来被称为Oracle。

MySQL历史

2. 前提准备

安装软件

  • Git
  • Linux Bash or Git Bash(For Windows)
  • Docker & Docker Compose
  • MySQL Workbench or Navicat for MySQL

下载示例源码

git clone https://github.com/Samurais/sql-in-10-mins.git
源自:SQL 必知必会(第四版)

示例数据ER图

  • 准备练习数据表结构(ER)
名称含义主要内容
Cusmtosers顾客表顾客ID、名字、地址、城市等
Orders订单表订单ID、订单时间、关联的顾客ID
OrderItems订单商品表商品ID、质量、订单数量
Products商品表商品价格、商品名称等
Vendors商品制造商表制造商名字、地址、城市等

  • 准备练习环境
  1. 启动MySQL Server
  2. 在Navicat中连接MySQL Server
  3. 创建练习Database 导入:tutorials/001.create.sql
  4. 导入数据到练习Database 导入:tutorials/001.populate.sql
    导入之后可以看到各个表和里面的数据:

3. SQL语法

表管理:table

语句含义
create创建
rename重命名
alter增加列
drop删除
-- 创建表 ,可以指定默认值
create table Products2
(
  prod_id    char(10)      NOT NULL ,
  vend_id    char(10)      NOT NULL ,
  prod_name  char(255)     NOT NULL ,
  prod_price decimal(8,2)  NOT NULL default 1.00,
  prod_desc  text          NULL 
);

-- 增加新字段
alter table Products2 add prod_type char(10) NOT NULL;

-- 重命名表
rename table Products2 to Products2Renamed;

-- 删除表
drop table Products2Renamed;

-- 复制表:
-- CREATE TABLE 新表 SELECT * FROM 旧表

查询:select

语句含义
select从表中选取数据
order by排序
where过滤
like模糊匹配
function函数
--select
-- 检索单个列
select prod_name from Products;
-- 检索多个列
select prod_id , prod_name ,prod_price from Products;
-- 检索多个列
select * from Products;
-- 检索不同的值(返回互不相同的元素)
select DISTINCT vend_id from Products;
-- 检索前5行
select prod_name from Products LIMIT 5;
-- 检索从第6行开始的连续4行
select prod_name from Products LIMIT 4 OFFSET 5;
-- 或简写为:
select prod_name from Products LIMIT 4,5;

-- order by 
-- 排序数据
select prod_name from Products order by prod_name;
-- 按多个列排序. 查找所有的商品Id,商品价格,商品名称。并按照价格排序,价格相同时,按名字排序
select prod_id,prod_price,prod_name from Products order by prod_price,prod_name;
-- 按多个列排序中也可以用数字代替(这里的数学是select中的位置),不建议这个做。意义不明确,可读性不好
select prod_id,prod_price ,prod_name  from Products order by 2 ,3;
-- 降序排序(默认是升序),单列
select prod_id,prod_price ,prod_name  from Products order by prod_price DESC;
-- 降序排序(默认是升序),多列(每列都要加上关键字)
select prod_id,prod_price ,prod_name  from Products order by prod_price DESC, prod_name DESC;

-- where
--过滤
select prod_name,prod_price from Products where prod_price = 3.49;
-- 小于
select prod_name,prod_price from Products where prod_price<10;
-- 不等于
select prod_id ,vend_id from Products where vend_id <> 'DLL01';
select prod_id ,vend_id from Products where vend_id != 'DLL01';
-- between and 
select prod_id,prod_price from Products where prod_price between 5 and 10;
--is null		(这里是从customers表中查)
select cust_id,cust_email from Customers where cust_email IS NULL;
select cust_id,cust_email from Customers where cust_email is not  NULL;

-- and or
-- and 	查找所有供货商为DLL01的,并且价格低于4美元的产品
select prod_id,prod_name  from Products where vend_id = 'DLL01'
       and prod_price<=4;
-- or	查找所有供货商DLL01和BRS01供应的商品
select prod_id ,prod_name from Products where vend_id = 'DLL01' or vend_id = 'BRS01';
-- and or查找所有供货商DLL01和BRS01供应的,并且价格高于10美元的商品 	
select prod_id ,prod_name,prod_price  from Products where (vend_id = 'DLL01' or vend_id = 'BRS01' ) and prod_price > 10;

-- IN	查找所有供货商DLL01和BRS01供应的商品
select prod_id ,vend_id from Products where vend_id in ('DLL01', 'BRS01');

-- NOT 	查找除了供货商DLL01供应的商品外所有其他的商品
select prod_id ,vend_id from Products where NOT vend_id = 'DLL01';
-- 相当于	
select prod_id ,vend_id from Products where vend_id != 'DLL01';

-- like 
-- 寻找所有以 'FISH'开头的产品
select prod_name from Products where prod_name like 'FISH%';
-- 寻找中间字段为'bean bag'的
select prod_name from Products where prod_name like '%bean bag %';
-- _通配符只匹配一个字符
select prod_id ,prod_name from Products where prod_name like '_ inch teddy bear';
-- []匹配,相当于[J%]和[M%]  mysql好像不支持
select cust_contact from Customers where cust_contact like '[JM]%';

-- function
-- 小写转大写函数 UPPER
select vend_name ,UPPER(vend_name) as vend_name_upcase from Vendors;
-- 查找2012年的所有订单,year也可以
select order_num from Orders where YEAR(order_date)=2012;

插入记录:insert

创建记录:用于向表格中插入新的行。

-- insert:在customers表中增加一行数据
insert into Customers(cust_id ,cust_name,cust_address,   cust_city,     cust_state,cust_zip)
            values( concat(FLOOR(RAND() * 1000000000), ''),       'Toy Land','123 Any Steet','New York',  'NY',       '11111');

更新记录:update

更新记录:用于更新表中已存在的记录。

--update:  给100000005增加电子邮件
update Customers  set cust_email='kim@thetoystore.com' where cust_id = '1000000005';
--   取消给100000005增加电子邮件
update Customers  set cust_email=NULL where cust_id = '1000000005';

删除记录:delete

删除记录:用于删除表中的行。

-- delete  删除100000006这一行
delete from Customers where cust_id = '1000000006';

函数:AVG, COUNT, MAX等

-- 求平均数	 求Products表中所有商品的平均价格
select AVG(prod_price) as avg_price from Products;
-- 统计所有顾客数(即统计一共有多少行)	求Customers表中顾客数
select count(*) as num_cust from Customers;
-- 只统计有邮件的顾客数
select count(cust_email)as n_email_cust from Customers;
-- 求最贵的商品价格
select max(prod_price) as max_price from Products;
select min(prod_price) as min_price from Products;
-- 求订单20005所有购买的商品数
select sum(quantity) as item_ordered from OrderItems where order_num= 20005;
-- 注意下面这个,它实际上求的是订单20005中买了几种商品
select count(*) from OrderItems where order_num=20005;
-- 聚集不同值 求供货商DLL01供应的商品价格的平均值(同样的价格的只算一次)
select AVG(DISTINCT prod_price) as avg_price from Products where vend_id='DLL01';
-- 组合聚集 求所有的商品数,最大商品价格,最小商品价格,平均价格
select count(*),min(prod_price),max(prod_price),avg(prod_price) from Products;
-- 在上面的语句中,重点关注一下 select count(*) from Products; 这个是求所有的行数,也就是所有的商品数!

-- 请列出最低价的products是哪些?
-- 错误的写法 select prod_name ,prod_price from `Products` where prod_price=min(prod_price); 
-- 正确的写法,使用子查询
select prod_name ,prod_price from `Products` where prod_price = (select min(prod_price) from `Products`);

函数:concat

拼接字符串:用于将两个字符串连接为一个字符串。

-- 拼接字符串 (mysql 不支持)
select CONCAT(vend_name,'(',vend_country, ')') from Vendors;

别名:as

别名:为表名称或列名称指定别名。

-- 别名,将查询结果保存为vend_title名 as 。
select CONCAT(vend_name,'(',vend_country, ')') AS vend_titile from Vendors;
-- 别名
select prod_id ,quantity,item_price ,quantity*item_price as total_price from OrderItems where order_num = 20008;

聚集:group by

聚集:表示根据by后面的字段进行分组。

-- 求各供应商供应的商品种类数(即 将Prodects以vend_id聚集)
select count(*) from Products group by vend_id;
-- 按 vend_id排序并分组数据
select vend_id,count(*) from Products group by vend_id;

-- Order表中求有两个及以上的订单的客户(having),将Orders以cust_id聚集
-- 使用Having过滤分组,该需求Where不能满足,Where作用于分组前,Having作用于分组后
select cust_id from Orders group by cust_id having count(*)>=2;

子查询:subquery

子查询:在多个表中查找,用到子查询,即一个select的结果作为另一个select的条件。

-- 1.  求订购了RGAN01这种商品的所有顾客。
-- 第一步,在OrderIterms表中求出购买了RGAN01的订单号
select order_num from OrderItems where prod_id='RGAN01';
-- 第二步,根据上面的订单号再在Orders表中求出对应的cust_id
select cust_id from Orders where (order_num='20007' or order_num='20008');
-- 可以把两句合成一句,即第一步的结果作为第二步的条件
select cust_id from Orders where order_num IN (select order_num from OrderItems where prod_id = 'RGAN01');

-- 2.  求Customers表中每个客户的订单总数
-- 需要注意的是,直接在orders表中根据cust_id来统计不正确,因为在Customers中的顾客只是orders表中cust_id的一部分。一个子集而已,所以这个是不完全正确的。
select cust_id ,count(*) from Orders group by cust_id;  
-- 我们可以一个一个的求,但是数据量很大时就不方便!
select count(*) from Orders where Orders.cust_id = '1000000001';
-- 当然,我们一起求啊,
-- 	select count(*) from Orders where Orders.cust_id = Customers.cust_id;
-- 但是这个出错了!ERROR 1054 (42S22): Unknown column 'Customers.cust_id' in 'where clause'
-- 这个cust_id是多少呢?数据库它并不知道。所以我们还需要一个select cust_id from Customers来得到一个cust_id的list
-- 最终正确的. 这个不是很好的做法,更容易理解的见后面的join用法
select cust_name,(select count(*) from Orders where Orders.cust_id = Customers.cust_id) from Customers;

连接:join

连接:用于根据两个或多个表中的列之间的关系,从这些表中查询数据。

-- 1.  求订购了RGAN01这种商品的所有顾客。
 -- 这里的order_num就是连接的字段    
 -- 然后OrderIterms表中的prod_id就是在另一侧的表中进行筛选
select cust_id from Orders ,OrderItems  where  Orders.order_num=OrderItems.order_num and OrderItems.prod_id = 'RGAN01';
-- 2.  求Customers表中每个客户的订单总数
select cust_name ,count(*) from Orders,Customers  where Orders.cust_id = Customers.cust_id group by Customers.cust_id;

自连接,外连接,全连接等

-- 1.自连接
-- 使用自连接的方法,实际上只不过是在一张表中了。但是你把它看做两张表即可。
select Customers.cust_name  from Customers where Customers.cust_name = Customers.cust_name and Customers.cust_contact ='Jim Jones';

-- 2. 外连接
--  检索custoerms表中所有顾客及其订单
-- 使用内连接(检索结果不正确,为空的检索不出来)
select Customers.cust_id ,Orders.order_num from Customers,Orders where Orders.cust_id=Customers.cust_id;
-- 交换 ‘=’ 两边的值也没有效果
select Customers.cust_id ,Orders.order_num from Customers,Orders where Customers.cust_id = Orders.cust_id;
-- 外左连接(结果正确!他是以custoerms表为标准,交换'='两边无所谓,主要是看Customers LEFT OUTER JOIN Orders这里有个记忆方法,出现left的就以左边的表为表中,出现right的就右边。)
select Customers.cust_id ,Orders.order_num from Customers LEFT OUTER JOIN Orders ON  Orders.cust_id=Customers.cust_id;
-- 外右连接(检索结果不正确,为空的检索不出来,因为它是以右边的Order为标准
select Customers.cust_id ,Orders.order_num from Customers RIGHT OUTER JOIN Orders ON  Orders.cust_id=Customers.cust_id;

-- 3.全连接
    -- 全连接相当于left和right的总和(mysql不支持)
    -- MySQL本身不支持full join(全连接),但可以通过union来实现

-- 4.连接与聚集函数的结合
-- 要检索所有每个顾客下的订单数
-- 这个使用的是内连接,不统计空的
select cust_name ,count(*) from Orders,Customers  where Orders.cust_id = Customers.cust_id group by Customers.cust_id;
-- 外连,统计空的
-- 查看RIGHT JOIN得到了什么
select * from Orders  RIGHT JOIN Customers ON Orders.cust_id = Customers.cust_id ; 
-- 要检索所有每个顾客下的订单数,支持空的
select cust_name,Orders.cust_id,count(Orders.cust_id) from Orders  RIGHT JOIN Customers ON Orders.cust_id = Customers.cust_id  GROUP BY Orders.cust_id ;

并集:union

合并:将多条select语句组合成一个结果集。

-- 例子: 现需要查询llinois、Indiana、和Michigan等美国几个州的所有顾客的名字,         
-- 还想知道不管位于哪个州的所有Fun4ALL顾客的名字。
-- 用union实现
select cust_contact from Customers where cust_state IN('MI','IN','IL') union select cust_name from Customers where cust_name = 'Fun4All';

视图:view

视图:视图是基于SQL 语句的结果集的可视化的表。

--求订购了RGAN01的所有顾客id 
-- 视图,简化查询。
-- 它是一个查询,并不包含具体的表的数据,也叫虚表
-- 它返回的是订购了任意产品的顾客。
create view ProductCustomers as select cust_id,prod_id from Orders ,OrderItems  where  Orders.order_num=OrderItems.order_num;
-- 查找购买了RGAN01的顾客id
select cust_id from  ProductCustomers where prod_id = 'RGAN01';

存储过程:procedure

存储过程:是一组为了完成特定功能的SQL语句集

-- 1.创建存储过程(函数),计算两个数的和
-- ----------------------------
-- Procedure structure for `proc_adder`
-- ----------------------------
DROP PROCEDURE IF EXISTS proc_adder;
DELIMITER ;;
CREATE PROCEDURE proc_adder (IN a int, IN b int, OUT sum int)
BEGIN
    -- Routine body goes here...
    DECLARE c int;
    if a is null then 
        set a = 0; 
    end if;
            
    if b is null then
        set b = 0;
    end if;

    set sum  = a + b;
END;;
DELIMITER ;

-- 调用
set @b=5;
call proc_adder(2,@b,@num);
SELECT @num;

4. MySQL运维管理

MySQL的运维工具很多,使用这些工具使得工作更加轻松。例如:

  • MySQL Workbench
    可以用MySQL Workbench设计和创建新的数据库图示,建立数据库文档,以及进行复杂的MySQL 迁移。
  • Navicat
    Navicat for MySQL是一套管理和开发MySQL或MariaDB的理想解决方案,支持单一程序,可同时连接到MySQL和MariaDB,是一个桌面版MySQL数据库管理和开发工具,易学易用。Navicat使用图形化的用户界面,可以让用户使用和管理更为轻松。

5. 延伸阅读

春松客服部署方案
春松客服数据词典
春松客服开发环境

开源智能客服系统

春松客服是 Chatopera 自主研发的,Apache2.0开源协议授权的智能客服系统,春松客服会不断增强客服系统的智能化,这包括利用自然语言处理、机器学习和语音识别等技术让客服工作更有效率、客服满意度更高、成本更低。

开源力量 社区共建

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐