https://zhuanlan.zhihu.com/p/114921777

坑与注意事项

group by 有一个原则,就是 select 后面的所有列中,没有使用聚合函数的列,必须出现在 group by 后面

数据库认识

5种类型数据库:

层次数据库,关系数据库,面向对象数据库,xml数据库,键值存储数据库。
mysql是关系数据库。即RDBMS。

数据库表结构,行称为记录,列称为字段。交汇处称为单元格。

sql语句分为三类:

  • ddl:data definition language,数据定义语言。用于创建或删除数据库,数据表等对象。
    • create:创建数据库和表等对象
    • drop:删除库和表
    • alter:修改库和表(列操作)
  • dml:data manipulation language,数据操纵语言,查询或变更记录(行)。(重点)
    • select:查询
    • insert:插入
    • update:更新
    • delete:删除
  • dcl:data control language,数据控制语言。确认或取消对数据的变更,设定对象的操作权限。
    • commit:确认变更
    • rollback:取消变更
    • grant:赋予权限
    • revoke:取消权限。

sql语句书写规范:

  • 分号结尾
  • 关键字不区分大小写,数据区分大小写;表名和字段根据操作系统不同,win不区分大小写,linux和mac区分。统一用小写。
  • 常数写法固定:日期,字符串用引号,数值直接写
  • 单词用半角或空行间隔
    • 常见注意事项如下:
  1. MySQL 本身不区分大小写,但强烈要求关键字大写,表名、列名用小写;
    1. 创建表时,使用统一的、描述性强的字段命名规则保证字段名是独一无二且不是保留字的,不要使 用连续的下划线,不用下划线结尾;最好以字母开头;
    2. 关键字右对齐,且不同层级的用空格或缩进控制,使其区分开,见样例二;
    3. 列名少的时候写在一行里无伤大雅;多的时候以及涉及到 CASE WHEN 或者聚合计算的时候,建 议分行写;个人习惯是逗号在列名前面,方便之后删除某些列,放列名后亦可;
    4. 表别名和列别名尽量用有具体含义的词组,不要用 a b c,不然以后 review 的时候会非常痛苦;
    5. 运算符前后都加一个空格;
    6. 当用到多个表时,请在所有列名前写上引用的表别名,不要嫌麻烦;
    7. 每条命令用分号结尾;
    8. 养成随手写注释的习惯,注释方法: • 单行注释 # 注释文字 • 单行注释 – 注释文字 • 多行注释: / 注释文字 /

语句与语法

数据库层面

  1. -- 创建数据库
  2. CREATE DATABASE < 数据库名称 > ;
  3. create database shop;
  4. -- 插入表数据
  5. CREATE TABLE < 表名 >
  6. ( < 列名 1> < 数据类型 > < 该列所需约束 > ,
  7. < 列名 2> < 数据类型 > < 该列所需约束 > ,
  8. < 列名 3> < 数据类型 > < 该列所需约束 > ,
  9. < 列名 4> < 数据类型 > < 该列所需约束 > ,
  10. .
  11. .
  12. .
  13. < 该表的约束 1> , < 该表的约束 2> ,……);
  14. CREATE TABLE product
  15. (product_id CHAR(4) NOT NULL,
  16. product_name VARCHAR(100) NOT NULL,
  17. product_type VARCHAR(32) NOT NULL,
  18. sale_price INTEGER ,
  19. purchase_price INTEGER ,
  20. regist_date DATE ,
  21. PRIMARY KEY (product_id));
  22. -- 删除表:无法恢复,只能重新插入
  23. DROP TABLE < 表名 > ;
  24. DROP TABLE product;
  25. -- 添加列
  26. ALTER TABLE < 表名 > ADD COLUMN < 列的定义 >;
  27. ALTER TABLE product ADD COLUMN product_name_pinyin VARCHAR(100);
  28. -- 删除列,无法恢复
  29. ALTER TABLE < 表名 > DROP COLUMN < 列名 >;
  30. ALTER TABLE product DROP COLUMN product_name_pinyin;
  31. -- 清空表:比dropdelete
  32. TRUNCATE TABLE TABLE_NAME;
  33. -- 更新记录
  34. UPDATE <表名>
  35. SET <列名> = <表达式> [, <列名2>=<表达式2>...];
  36. WHERE <条件>; -- 可选,非常重要。
  37. ORDER BY 子句; --可选
  38. LIMIT 子句; --可选
  39. -- 修改所有的注册时间,set后可多写
  40. UPDATE product
  41. SET regist_date = '2009-10-10';
  42. -- 仅修改部分商品的单价
  43. UPDATE product
  44. SET sale_price = sale_price * 10
  45. WHERE product_type = '厨房用具';
  46. UPDATE product
  47. SET regist_date = NULL
  48. WHERE product_id = '0008';
  49. -- 合并后的写法
  50. UPDATE product
  51. SET sale_price = sale_price * 10,
  52. purchase_price = purchase_price / 2
  53. WHERE product_type = '厨房用具';
  54. -- 插入一行
  55. INSERT INTO <表名> (列1, 2, 3, ……) VALUES (值1, 2, 3, ……);
  56. -- 包含列清单
  57. INSERT INTO productins (product_id, product_name, product_type, sale_price, purchase_price, regist_date) VALUES ('0005', '高压锅', '厨房用具', 6800, 5000, '2009-01-15');
  58. -- 省略列清单
  59. INSERT INTO productins VALUES ('0005', '高压锅', '厨房用具', 6800, 5000, '2009-01-15');
  60. -- 查询
  61. SELECT <列名>, ……
  62. FROM <表名>
  63. WHERE <条件表达式>;
  64. -- 聚合查询
  65. -- 计算全部数据的行数(包含NULL
  66. SELECT COUNT(*)
  67. FROM product;
  68. -- 计算NULL以外数据的行数
  69. SELECT COUNT(purchase_price)
  70. FROM product;
  71. -- 计算销售单价和进货单价的合计值
  72. SELECT SUM(sale_price), SUM(purchase_price)
  73. FROM product;
  74. -- 计算销售单价和进货单价的平均值
  75. SELECT AVG(sale_price), AVG(purchase_price)
  76. FROM product;
  77. -- MAXMIN也可用于非数值型数据
  78. SELECT MAX(regist_date), MIN(regist_date)
  79. FROM product;
  80. -- 计算去除重复数据后的数据行数
  81. SELECT COUNT(DISTINCT product_type)
  82. FROM product;
  83. -- 是否使用DISTINCT时的动作差异(SUM函数)
  84. SELECT SUM(sale_price), SUM(DISTINCT sale_price)
  85. FROM product;
  86. -- 表分组
  87. SELECT <列名1>,<列名2>, <列名3>, ……
  88. FROM <表名>
  89. GROUP BY <列名1>, <列名2>, <列名3>, ……;
  90. -- 按照商品种类统计数据行数
  91. SELECT product_type, COUNT(*)
  92. FROM product
  93. GROUP BY product_type;
  94. -- 不含GROUP BY
  95. SELECT product_type, COUNT(*)
  96. FROM product
  97. -- 分组与限定
  98. -- 数字
  99. SELECT product_type, COUNT(*)
  100. FROM product
  101. GROUP BY product_type
  102. HAVING COUNT(*) = 2;
  103. -- 错误形式(因为product_name不包含在GROUP BY聚合键中)
  104. SELECT product_type, COUNT(*)
  105. FROM product
  106. GROUP BY product_type
  107. HAVING product_name = '圆珠笔';
  108. -- 视图:保存select语句的结果
  109. CREATE VIEW <视图名称>(<列名1>,<列名2>,...) AS <SELECT语句>
  110. CREATE VIEW view_shop_product(product_type, sale_price, shop_name)
  111. AS
  112. SELECT product_type, sale_price, shop_name
  113. FROM product,
  114. shop_product
  115. WHERE product.product_id = shop_product.product_id;
  116. -- 修改视图
  117. ALTER VIEW <视图名> AS <SELECT语句>
  118. ALTER VIEW productSum
  119. AS
  120. SELECT product_type, sale_price
  121. FROM Product
  122. WHERE regist_date > '2009-09-11';
  123. DROP VIEW <视图名1> [ , <视图名2> …]
  124. DROP VIEW productSum;

数据类型

integer:整数

char:长字符串

存储达不到最大长度,用半角空格补足,浪费空间

varchar:可变长字符串

不补足

date:年月日

float

类型转换(todo)

约束

not null :非空
primary key:主键
default xx:默认值

查询

  • select
    • select :全部列,增加的自定义列放前面,后面可再加
    • select distinct row_name:删除重复数据
    • 可使用别名自定义列名
  • where:限定行/记录的条件
  • having:限定列的条件,用在group by后
  • 分组group by:

    • null会单独作为一组特殊数据
    • 是对筛选后数据处理,写在select…from…where之后
    • group by 中不能使用别名,因为执行顺序在select前
    • 使用了group by后select 只能是聚合的列
    • 计算分类的合计:group by xx with rollup
      1. SELECT product_type
      2. ,regist_date
      3. ,SUM(sale_price) AS sum_price
      4. FROM product
      5. GROUP BY product_type, regist_date WITH ROLLUP
  • order by:对查询结果排序

    • order by xx asc/desc
    • 结果含有null,会放在开头或结尾
    • 子句可以使用别名,因为执行顺序在select后
  • 视图:可复用,被处理过的select语句的结果
    • 虚拟表
    • 可被更新,含有下列情况不可被更新:
      • 聚合函数 SUM()、MIN()、MAX()、COUNT() 等。
      • DISTINCT 关键字。
      • GROUP BY 子句。
      • HAVING 子句。
      • UNION 或 UNION ALL 运算符。
      • FROM 子句中包含多个表。
    • 视图与原表的关系
      • 原表数据更新,视图中相关数据也会被更新。反之亦然
      • 视图是原表的一个窗口,用于看到部分原表数据或对原表进行处理。
  • 子查询
    • from子句是另一个select语句, from ( xxxx) as xx
    • 一次性,保存下来就是视图
    • 子句是标亮单一值(使用了聚合函数)也可以用在:where,group by,having,order by子句。
    • 关联子查询:主查询与子查询通过标志连结(比如where条件),一般会给表设置别名。

函数(常用30-50)

算数函数

  • abs(数值):绝对值
  • mod(被除数,除数):取余数
  • round(对象数值,保留小数的位数):四舍五入。保留小数的位数可为参数,注意可能出错。

    字符串函数

  • concat(str1,str2, str3):拼接

  • length(str):长度
  • lower(str):转小写
  • upper(str):转大写
  • replace(src, str_before, str_after):替换
  • substring(对象字符串 FROM 截取的起始位置 FOR 截取的字符数 ):截取字符串。索引值起始为1

    日期函数

  • current_date():当前年月日

  • current_time():当前时间:时分秒
  • current_timestamp():当前时间,年月日时分秒
  • extract(日期元素 FROM 日期):截取日期元素

    • 日期元素可以是:year,month,day,hour,minute,second

      转换函数

  • cats(转化前值 as 想要转化的数据类型) 类型转换

    • 数据类型:singed integer,date。。。
  • coalesce(data1, data2, data3…):将null值转化为其他值

    • 参数可变
    • 返回参数中从左开始第一个不是null的值

      聚合函数

  • count(),avg(),max(),min()

  • count(*)包括null,其它情况聚合函数都会排除null,参数是具体列名
  • max/min适用于几乎所有,sum/avg适用于数值类
  • distinct排除重复值,可用于参数中

谓词

返回真值的函数

  • 真值:true,false,unkonwn
  • 谓词:
    • like:字符串匹配
      • like ‘dd%’:0+,匹配开头
      • like ‘dd%dd’:匹配中间
      • like ‘%dd’:匹配结尾
      • 符号:%匹配0+个任意字符,_匹配1+各任意字符
    • between:范围查询
      • 范围查询,需要2个参数,包含两个临界值
      • between 100 and 1000:[100, 1000]
    • is null,is not null
      • null不能用=判断,要用is null 或is not null
    • in: 简写的or
      • 简写的or,in(10,50, 100):是三者之一即可
      • 有in 也有not in
      • 不管是in 还是not in,结果都不包括null
      • 支持子查询,in(select 子句):更灵活
    • exists
      • 可以用in/not in替代
      • 判断是否存在满足某种条件的记录:返回true/false
      • 参数通常是个子查询:exist(select 子句)
      • 有exist也有not exist

case 表达式

分为简单表达式与搜索表达式。后者包含前者,可只学习后者。
依次判断when是否为真,是执行then后语句,都不满足,执行else后表达式。end不要省略。
else 不写则默认else null。

  1. CASE WHEN <求值表达式> THEN <表达式>
  2. WHEN <求值表达式> THEN <表达式>
  3. WHEN <求值表达式> THEN <表达式>
  4. .
  5. .
  6. .
  7. ELSE <表达式>
  8. END
  9. SELECT product_name,
  10. CASE WHEN product_type = '衣服' THEN CONCAT('A : ',product_type)
  11. WHEN product_type = '办公用品' THEN CONCAT('B : ',product_type)
  12. WHEN product_type = '厨房用具' THEN CONCAT('C : ',product_type)
  13. ELSE NULL
  14. END AS abc_product_type
  15. FROM product;
  16. -- 实现行转列
  17. -- 对按照商品种类计算出的销售单价合计值进行行列转换
  18. SELECT SUM(CASE WHEN product_type = '衣服' THEN sale_price ELSE 0 END) AS sum_price_clothes,
  19. SUM(CASE WHEN product_type = '厨房用具' THEN sale_price ELSE 0 END) AS sum_price_kitchen,
  20. SUM(CASE WHEN product_type = '办公用品' THEN sale_price ELSE 0 END) AS sum_price_office
  21. FROM product;
  22. +-------------------+-------------------+------------------+
  23. | sum_price_clothes | sum_price_kitchen | sum_price_office |
  24. +-------------------+-------------------+------------------+
  25. | 5000 | 11180 | 600 |
  26. +-------------------+-------------------+------------------+
  27. 1 row in set (0.00 sec)
  28. -- CASE WHEN 实现数字列 score 行转列
  29. SELECT name,
  30. SUM(CASE WHEN subject = '语文' THEN score ELSE null END) as chinese,
  31. SUM(CASE WHEN subject = '数学' THEN score ELSE null END) as math,
  32. SUM(CASE WHEN subject = '外语' THEN score ELSE null END) as english
  33. FROM score
  34. GROUP BY name;
  35. +------+---------+------+---------+
  36. | name | chinese | math | english |
  37. +------+---------+------+---------+
  38. | 张三 | 93 | 88 | 91 |
  39. | 李四 | 87 | 90 | 77 |
  40. +------+---------+------+---------+
  41. -- CASE WHEN 实现文本列 subject 行转列
  42. SELECT name,
  43. MAX(CASE WHEN subject = '语文' THEN subject ELSE null END) as chinese,
  44. MAX(CASE WHEN subject = '数学' THEN subject ELSE null END) as math,
  45. MIN(CASE WHEN subject = '外语' THEN subject ELSE null END) as english
  46. FROM score
  47. GROUP BY name;
  48. +------+---------+------+---------+
  49. | name | chinese | math | english |
  50. +------+---------+------+---------+
  51. | 张三 | 语文 | 数学 | 外语 |
  52. | 李四 | 语文 | 数学 | 外语 |
  53. +------+---------+------+---------+

关键词的书写顺序和执行顺序

FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。

语法顺序:
select [distinct]
from
join on
where
group by
having
union
order by

执行顺序:
from
join on
where
group by
having
select
distinct
union
order by

运算符

算数:+, -, *, /(取小数)

比较:=, <>, >=, <=, >, <

逻辑:not 否定, WHERE NOT sale_price >= 1000; and, or

and优先于or,可以用括号提高优先级。

由于存在null(不确定值),因此真值表为三值逻辑
image.png
注意:
4种结果为null的情况:
ture and null = null
false or null = null
null and null = null
null or null = null
2种与null操作有结果的情况:
ture or null = true/1
false and null = false/0
image.png

与null的比较:结果都为null
image.png

集合运算

并集:union,行合并,可以用or替代

合并会去重,如果要保留重复行,用union all 替代union

  1. SELECT product_id,product_name,product_type
  2. ,sale_price,purchase_price
  3. FROM PRODUCT
  4. WHERE sale_price<800
  5. UNION
  6. SELECT product_id,product_name,product_type
  7. ,sale_price,purchase_price
  8. FROM PRODUCT
  9. WHERE sale_price>1.5*purchase_price;

差集/交集:not in
对称差:并集-交集:

  1. -- 使用 NOT IN 实现两个表的差集
  2. SELECT *
  3. FROM Product
  4. WHERE product_id NOT IN (SELECT product_id FROM Product2)
  5. UNION
  6. SELECT *
  7. FROM Product2
  8. WHERE product_id NOT IN (SELECT product_id FROM Product)

连结:增加列,xx join

  • 多表信息获取,将结果显示在一个表
  • 连结一般会对两个表取别名,在on里用别名.列名的形式引用,同时在select里也可以用到别名。
  • 连结后的内容,根据select的顺序。
  • on是连结的条件。
  • 后面还可以增加where子句,进一步对连结后结果进行筛选。
  • 关于on和where,可以分开,也可以现在各自的子句里where筛选后再连结。
  • 亦可增加group by分组,在on之后。
  • 子连结可用子查询实现。
  • inner join换成natural join,则会根据两个表都包含的列名进行连结。
  • 可使用连结实现交集:在on里限定条件
  • 内连结:保留共同的,左/右连结:调换表顺序,实际一致。一定会输出主表全部。全外连结,输出两表所有。不能被关联的用null补足。 ```sql — 内连结 FROM INNER JOIN ON — 左连结
    FROM LEFT OUTER JOIN ON — 右连结
    FROM RIGHT OUTER JOIN ON — 全外连结 FROM FULL OUTER JOIN ON

SELECT SP.shop_id ,SP.shop_name ,SP.product_id ,P.product_name ,P.product_type ,P.sale_price ,SP.quantity FROM ShopProduct AS SP INNER JOIN Product AS P ON SP.product_id = P.product_id;

SELECT SP.shop_id ,SP.shop_name ,MAX(P.sale_price) AS max_price FROMshopproduct AS SP INNER JOINproduct AS P ON SP.product_id = P.product_id GROUP BY SP.shop_id,SP.shop_name

  1. <a name="opJ5h"></a>
  2. ## 窗口函数
  3. 有选择地对部分数据进行汇总,计算和排序。
  4. - partition by:用于分组,语义类似group by,可省略
  5. - order by:排序
  6. - 窗口函数
  7. - 聚合函数:逐行累计
  8. - sum()
  9. - max()
  10. - min()
  11. - 累计还可以限制累计行的范围:
  12. - rows n preceding:之前的n行+自身行
  13. - rows between n1 preceding and n2 following:之前n1行+自身行+之后n2行
  14. - rows n following:自身行+之后n行
  15. - 专用排序
  16. - rank():相同位次,跳过之后位次。1,1,1,4
  17. - dense_rank():相同位次并列不跳过。1,1,1,2
  18. - row_number():唯一连续位次。1,2,3,4
  19. ```sql
  20. <窗口函数> OVER ([PARTITION BY <列名>]
  21. ORDER BY <排序用列名>)
  22. SELECT product_name
  23. ,product_type
  24. ,sale_price
  25. ,RANK() OVER (PARTITION BY product_type
  26. ORDER BY sale_price) AS ranking
  27. FROM product
  28. SELECT product_name
  29. ,product_type
  30. ,sale_price
  31. ,RANK() OVER (ORDER BY sale_price) AS ranking
  32. ,DENSE_RANK() OVER (ORDER BY sale_price) AS dense_ranking
  33. ,ROW_NUMBER() OVER (ORDER BY sale_price) AS row_num
  34. FROM product
  35. SELECT product_id
  36. ,product_name
  37. ,sale_price
  38. ,SUM(sale_price) OVER (ORDER BY product_id) AS current_sum
  39. ,AVG(sale_price) OVER (ORDER BY product_id) AS current_avg
  40. FROM product;
  41. SELECT product_id
  42. ,product_name
  43. ,sale_price
  44. ,AVG(sale_price) OVER (ORDER BY product_id
  45. ROWS 2 PRECEDING) AS moving_avg
  46. ,AVG(sale_price) OVER (ORDER BY product_id
  47. ROWS BETWEEN 1 PRECEDING
  48. AND 1 FOLLOWING) AS moving_avg
  49. FROM product

关键字

as:列和表的别名,用于自定义查询显示的列名或者多表查询时,为了方便给表起别名。
if exist

数据库,excel,python处理的比较