SQL基础教程(1)

以下基于mysql

一个商品表

create table Product (
product_id char(4) not null,
product_name varchar(100) not null,
product_type varchar(32) not null,
sale_price integer ,
purchase_price integer ,
regist_date date ,
primary key (product_id));

导入sql语句

// 进入mysql命令行
source 路径

删除表

drop table product

重命名表

rename table Poduct to Product

增加列

alter table product add column product_name_pinyin varchar(100);

删除列

alter table product drop column product_name_pinyin;

更改列为主键

alter table product add primary key (product_id);

插入行

begin transaction;
INSERT INTO Product VALUES ('0001', 'T恤衫', '衣服', 1000, 500, '2019-12-30');
INSERT INTO Product VALUES ('0002', '打孔器', '办公用品', 500, 320, '2019-12-29');
INSERT INTO Product VALUES ('0003', '运动T恤','衣服', 4000, 2800, NULL);
INSERT INTO Product VALUES ('0004', '菜刀', '厨房用具', 3000, 2800, '2019-12-28');
INSERT INTO Product VALUES ('0005', '高压锅', '厨房用具', 6800, 5000, '2019-12-27');
INSERT INTO Product VALUES ('0006', '叉子', '厨房用具', 500, NULL, '2019-12-26');
INSERT INTO Product VALUES ('0007', '擦菜板', '厨房用具', 880, 790, '2019-12-25');
INSERT INTO Product VALUES ('0008', '圆珠笔', '办公用品', 100, NULL, '2019-12-24');
commit;

SELECT

查询列设置别名
select product_id as id, product_name as name, purchase_price as price from product;

select product_id as "商品编号", product_name as "商品名称", purchase_price as "进货单价" from product;

设置汉语要用双引号""

设置常数显示
select '商品' as string, 38 as number, '2019-02-24' as date, product_id, product_name from product;

显示结果每一行都会有 商品,38,2019-02-24这三个数据

从结果中删除重复行
select distinct product_type from product;

select distinct product_type, regist_date from product;

如果有NULL,会被当成一类来显示

where
select product_name, product_type from product where product_type='衣服';

select product_name from product where product_type = '衣服';
注释
-- 单行注释

/* 多行注释
*/

算数运算符

  • +
  • -
  • *
  • /
select product_name, sale_price, sale_price * 2 as "sale_price_x2" from product;

比较运算符

-- 等于
select product_name, product_type from product where sale_price = 500;
-- 不等于
select product_name, product_type from product where sale_price <> 500;
/*
还有
>=
>
<=
<
*/

联合使用

select product_name, sale_price, purchase_price from product where sale_price - purchase_price >= 500;

NULL不能比较,只能用 is null & is not null 来判断

select product_name, purchase_price from product where purchase_price is null;

逻辑运算符

not
select product_name, product_type, sale_price from product where not sale_price >= 1000;
and & or
select product_name, purchase_price from product where product_type='厨房用具' and sale_price >= 3000;

select product_name, purchase_price from product where product_type='厨房用具' or sale_price >= 3000;

select product_name, product_type, regist_date from product where product_type='办公用品' and (regist_date = '2019-12-29' or regist_date = '2019-12-24');

and运算符优先级高于or,所以要加上括号

聚合与排序

对表进行聚合查询
  • COUNT: 计算表中的记录数(行数)
  • SUM: 计算表中数值列中数据的合计值
  • AVG: 计算表中数值列中数据的平均值
  • MAX: 求出表中任意列中数据的最大值
  • MIN: 求出表中任意列中数据的最小值
  • DISTINCT: 删除重复值
-- 计算行数
select count(*) from product;
-- count(*)会得到包含NULL的数据行数,count(列名)会得到NULL之外的数据行数

-- 计算合计值
select sum(sale_price) from product;

-- 计算平均值
select avg(sale_price) from product;
-- avg自动把NULL排除,所以这时候数量是6

-- 最大值,最小值
select max(sale_price), min(purchase_price) from product;
-- min和max理论上适用于任何数据类型的列,字符串、日期等的比较也不会有问题,但是SUM/AVG不行

-- 计算删除重复数据后的数据行数
select count(distinct product_type) from product;
-- 所有的聚合函数都可以使用distinct

所有包含列名的聚合函数,都会把NULL排除在外

对表进行分组

先把表分成几组,在进行汇总处理

GROUP BY
-- 将数据按照product_type分类,并计算每个分类的数量
select product_type, count(*) from product group by product_type;

select purchase_price, count(*) from product where product_type='衣服' group by purchase_price;
  1. 如果有group by,那么select语句只能使用group by指定的列名
  2. group by 不能使用 select 中列的别名
  3. group by 字句结果的显示是无序的
  4. 只有 select, having, order by 字句中能够使用聚合函数
为聚合结果指定条件
  • 使用COUNT函数等对表中数据进行汇总操作时,为其指定条件的不是where字句,而是HAVING字句
  • 聚合函数可以在SELECT字句、HAVING字句和ORDER BY字句中使用
  • HAVING字句要写在GROUP BY字句之后
  • WHERE字句用来指定数据行的条件,HAVING字句用来指定分组的条件
-- 按照商品种类进行分组后的结果中,取出”包含的数据行数为2行的组“
select product_type, count(*) from product group by product_type having count(*) = 2;
-- 取出销售单价大于等于2500的分组数据
select product_type, avg(sale_price) from product group by product_type having avg(sale_price) >= 2500;

聚合键所对应的条件不应该卸载HAVING字句当中,而应该书写在WHERE字句当中

对查询结果进行排序
select product_id, product_name, sale_price, purchase_price from product order by sale_price;

select product_id, product_name, sale_price, purchase_price from product order by sale_price DESC;

-- order by 字句中可以使用列的别名
select product_id as id, product_name, sale_price as sp, purchase_price from product order by sp, id;

-- select字句中未包含的列也可以在order by字句中使用
select product_name, sale_price, purchase_price from product order by product_id;
-- 在order by字句中可以使用select字句中未使用的列和聚合函数
select product_type, count(*) from product group by product_type order by count(*);

未指定ORDER BY字句中排列顺序时会默认使用升序进行排列
排序键中包含NULL时,会在开头或末尾进行汇总

为什么order by可以使用别名,group by不可以呢?

这里要知道使用HAVING字句时SELECT语句的顺序

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY

SELECT字句的执行顺序是在GROUP BY字句之后,ORDER BY字句之前,因此在执行GROUP BY字句时,SELECT语句中定义的别名无法被识别

数据更新

数据的插入
-- 通常的insert
insert into ProductIns (product_id, product_name, product_type, sale_price, purchase_price, regist_date) values ('0001', 'T恤衫', '衣服', 1000, 500, '2009-09-20');
-- 多行insert
insert into ProductIns values ('0002', '打孔器', '办公用品', 500, 320, '2009-09-11'), ('0003', '运动T恤', '衣服', 4000, 2800, NULL), ('0004', '菜刀', '厨房用具', 3000, 2800, '2009-09-20');
-- 省略列清单
insert into ProductIns values ('0005', '高压锅', '厨房用具', 6800, 5000, '2009-01-15');
-- 插入NULL
insert into ProductIns (product_id, product_name, product_type, sale_price, purchase, regist_date) values ('0006', '叉子', '厨房用具', 500, NULL, '2009-09-20');
-- 插入默认值(显式方式)
insert into ProductIns (product_id, product_name, product_type, sale_price, purchase, regist_date) values ('0007', '擦菜板', '厨房用具', DEFAULT, 790, '2009-04-28');
-- 插入默认值(隐式方式)
insert into ProductIns (product_id, product_name, product_type, purchase, regist_date) values ('0007', '擦菜板', '厨房用具', 790, '2009-04-28');

-- 使用显式方式更容易理解
从其他表中复制数据
insert into ProductCopy (product_id, product_name, product_type, sale_price, purchase_price, regist_date) select product_id, product_name, product_type, sale_price, purchase_price, regist_date from Product;

-- 多种多样的select
insert into ProductType (product_type, sum_sale_price, sum_purchase_price) select product_type, sum(sale_price), sum(purchase_price) from Product group by product_type;
数据的删除

drop table 删除整个表,delete 删除表中的数据

-- 清空表
delete from ProductType;
-- 根据条件删除
delete from Product where sale_price >= 4000;

delete只能使用where字句,group by、having、order by不能用,没有意义

truncate与delete相似,但是前者只能删除表中的全部数据,而不能通过where字句指定条件来删除部分数据,因为它只能删除全部,所以处理速度别delete更快

数据的更新

update

update Product set regist_date='2009-10-10';

-- 指定条件
update Product set sale_price = sale_price * 10 where product_type='厨房用具';

-- 使用NULL进行更新
update Product set regist_date = NULL where product_id='0008';

-- 多列更新
update Product set sale_price = sale_price * 10, purchase_price = purchase_price / 2 where product_type = '厨房用具';
事务
  • 事务是需要在同一个处理单元中执行的一系列更新处理的集合。通过使用事务,可以对数据库中的数据更新处理的提交和取消进行管理
  • 事务处理的终止指令包括COMMIt(提交处理)和ROLLBACK(取消处理)两种
  • DBMS的事务具有原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)四种特性,统称为ACID特性

事务是需要在同一个处理单元中执行的一系列更新处理的集合

start transaction;

update Product set sale_price = sale_price+1000 where product_id='0001';

commit;

-- rollback 回滚到开始事务之前的状态

当开启一个连接对数据库进行操作时,启动事务,修改,还没有提交,此时启动另一个连接,是看不到还没有提交的事务修改后的数据的。这时候如果执行 delete 操作,就会阻塞住,只有等之前的事务提交后才会继续执行delete

复杂查询

视图

视图并不保存数据,它保存的是select语句

create view ProductSum (product_type, cnt_product) as select product_type, count(*) from product group by product_type;

select product_type, cnt_product from ProductSum;

drop view ProductSum;

从视图中查找就是调用视图的select语句

视图支持嵌套,但不建议,影响性能

从表中更新数据,查询视图也会同步更新,因为本质是select。从视图更新数据,也会影响到表,但是有限制

  • SELECT子句中未使用DISTINCT
  • FROM字句中只有一张表
  • 未使用GROUP BY子句
  • 未使用HAVING子句
子查询

一张一次性视图

select product_type, cnt_product from (select product_type, count(*) as cnt_product from Product group by product_type) as ProductSum;

-- 就是将用来定义视图的select语句直接用于from字句当中,as ProductSum就是子查询的名称,但是是一次性的,执行完之后就消失

子查询作为内存查询会首先执行,且没有层数上的限制

标量子查询

只能返回表中某一行的某一列的值

-- 找出售价高于平均售价的产品
select product_id, product_name, sale_price from Product where sale_price > avg(sale_price);

-- 很明显上面是错误的写法,where字句不能有聚合函数,所以这里就要用到标量子查询
select product_id, product_name, sale_price from Product where sale_price > (select avg(sale_price) from Product);

标量子查询的书写位置不局限于where字句中,通常任何可以使用单一值的位置都可以使用

-- select子句使用标量子查询
select product_id, product_name, sale_price, (select avg(sale_price) from Product) as avg_price from Product;

-- having子句使用标量子查询
select product_type, avg(sale_price) from Product group by product_type having avg(sale_price) > (select avg(sale_price) from Product);

注意:标量子查询的结果一定不能返回多行

关联子查询

如果要找出产品售价高于每个商品种类的平均售价的产品,理论上

select product_id, product_name, sale_price from Product where sale_price > (select avg(sale_price) from Product group by product_type);

这里用了标量子查询,但是是错误的,标量子查询的返回结果必须是单一值,这里返回了多个值(每个商品种类的平均售价),比较是不成立的

用关联子查询来解决

select product_id, product_name, sale_price from Product as P1 where sale_price > (select avg(sale_price) from Product as P2 where P1.product_type = P2.product_type group by product_type);

关联子查询相比于标量子查询增加了一个判断,用来找出子查询返回多个结果的相匹配的那一个,这样就可以用来比较了,要注意关联名称的范围

来自 https://leejnull.github.io/2020/01/08/2020-01-08-01/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容

  • 还是那些欲望 嫉妒心在蔓延 虚荣心在膨胀 它指引着欲望 摆脱啊 挣...
    沛沛沛沛沛沛阅读 398评论 0 3
  • 静观窗外,玉兰花独自盛开 片片飞花如雪 一抹素云卸落枝头,便再无等待 2019.03.19.12.34
    做人如莲阅读 252评论 0 2
  • (一)一眼执念,遭遇波折 我不知道是否有人和我一样,从考上大学的那一刻起,就决心考研。也许考研之于他人,是众多选...
    田小迟阅读 644评论 17 16
  • 印象中母亲是一个胆小、柔弱、老实的女人。 她从不和人大声说话,有什么事也是偷偷把我们叫到跟前说。 她没有什么知己的...
    何一二来了阅读 257评论 0 1
  • 我向来比较认真,做什么都一板一眼,挺努力的,但不算刻苦。 小学前几年成绩中游,后来碰到了很欣赏我的老师,然后成绩开...
    微轻阅读 546评论 0 0