一、DBMS (DataBase Management System)

DBMS = 多个数据库(DB) + 管理程序

关系型数据库(RDBMS)就是建立在关系模型基础上的数据库 (如Oracle, mySql, Sql server),SQL就是关系型数据库的查询语言。

相比于SQL,NoSQL泛指非关系型数据库,包括了键值型数据库(如Redis)、文档型数据库(如MongoDB)、搜索引擎(如Elasticsearch)和列存储等,除此以外还包括图形数据库。

列式数据库是相对于行式存储的数据库,Oracle、MySQL、SQL Server等数据库都是采用的行式存储(Row-based),而列式数据库是将数据按照列存储到数据库中,这样做的好处是可以大量降低系统的I/O,适合于分布式文件系统,不足在于功能相对有限。

NoSQL数据库四大类型:键值数据库列族数据库文档数据库图形数据库


二、Sql语句

SQL 分为:数据操作语言 (DML) ,数据查询语言DQL, 数据定义语言 (DDL), 数据控制语言(DCL)

DML——数据操作语言

  • UPDATE - 更新数据库表中的数据 / REPLACE
  • DELETE - 从数据库表中删除数据
  • INSERT INTO - 向数据库表中插入数据

DQL——数据查询语言:

基本结构是由SELECT子句,FROM子句,WHERE子句组成的查询块:

SELECT <字段名表>
FROM <表或视图名>
WHERE <查询条件>

执行顺序*

  1. FROM
  2. ON
  3. JOIN
  4. WHERE
  5. GROUP BY
  6. HAVING
  7. WINDOW functions
  8. SELECT
  9. DISTINCT
  10. UNION
  11. ORDER BY
  12. LIMIT and OFFSET
SELECT DISTINCT 列名称 FROM 表名称
SELECT 列名称 FROM 表名称 WHERE 列 运算符 值
/*例子*/
SELECT * FROM Persons WHERE FirstName='Thomas' AND LastName='Carter' ORDER BY Company DESC

INSERT INTO 表名称 VALUES (值1, 值2,....)
INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)

UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
REPLACE INTO 表名称 VALUES (值1, 值2,....)  --有没有都插入

DELETE FROM 表名称 WHERE 列名称 = 值

DDL——数据定义语言:

创建或删除表格,也可以定义索引(键),规定表之间的链接,以及施加表间的约束。

  • CREATE DATABASE - 创建新数据库
  • ALTER DATABASE - 修改数据库
  • CREATE TABLE - 创建新表
  • ALTER TABLE - 变更(改变)数据库表 (ADD, DROP, ALTER (Sql server), MODIFY column)
  • DROP TABLE - 删除表
  • CREATE INDEX - 创建索引(搜索键)
  • DROP INDEX - 删除索引
--创建表
CREATE TABLE Persons
(
Id_P int NOT NULL PRIMARY KEY,
LastName varchar(255) NOT NULL,
FirstName varchar(255) UNIQUE,
Address varchar(255),
City varchar(255),
CONSTRAINT uc_PersonID UNIQUE (Id_P,LastName),  --多个列定义 UNIQUE 约束
FOREIGN KEY (Id_O) REFERENCES Persons(Id_O)    --外键约束
)

--创建索引
CREATE INDEX index_name
ON table_name (column_name)

DCL—数据控制语言 (GRANT 授权,REVOKE,COMMIT 提交,ROLLBACK 回滚)

--查看指定用户的权限
SHOW GRANTS FOR '用户名'@ 'IP地址'

--给用户分派在指定的数据库上的指定的权限
GRANT 权限1, … , 权限n ON 数据库.表名 TO '用户名'@'IP地址'
GRANT CREATE,ALTER,DROP,INSERT,UPDATE,DELETE,SELECT ON mydb1.* TO 'user1'@'localhost';
GRANT ALL ON 数据库.* TO '用户名'@'IP地址'

--撤销权限
REVOKE 权限1, … , 权限n ON 数据库.表名 FROM '用户名'@'IP地址

提交的三种方式

  1. 显式提交,用COMMIT直接完成提交为显式提交
  2. 隐式提交,用SQL语句间接完成的提交为隐式提交,这些命令有:ALTER , CONNECT, CREATE, DISCONNECT, DROP, EXIT, GRANT, QUIT, REVOKE
  3. 自动提交 把AUTOCOMMIT 设为ON 系统自动提交:  SET AUTOCOMMIT ON;

1. Join语句

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

  • (INNER) JOIN: 如果表中有至少一个匹配,则返回行
  • LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
  • RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
  • FULL JOIN: 只要其中一个表中存在匹配,就返回行
SELECT column_name(s)
FROM table_name1
INNER JOIN table_name2
ON table_name1.column_name=table_name2.column_name

SELECT column_name(s)
FROM table_name1
INNER JOIN table_name2
USING(column_name)

2. Union (ALL) 操作

合并两个或多个 SELECT 语句的结果集。UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。

Union和Union All区别:

  • Union: 对两个结果集进行并集操作, 不包括重复行; 会对获取的结果进行排序操作
  • Union All: 对两个结果集进行并集操作; 不会对获取的结果进行排序操作

3. SQL通配符

通配符描述
%代表零个或多个字符
_仅替代一个字符
[charlist]字符列中的任何单一字符

[^charlist] 或者 [!charlist]

不在字符列中的任何单一字符
SELECT * FROM Persons WHERE City LIKE '%lon%'

4. SQL函数

函数描述示例
CAST()转换为指定数据类型CAST(expr as 数据类型)
UCASE()把字段的值转换为大写SELECT UCASE(column_name) FROM table_name
FIRST()返回指定的字段中第一个记录的值SELECT FIRST(column_name) FROM table_name
MID()用于从文本字段中提取字符
(start起始值是 1)
SELECT MID(column_name,start[,length]) FROM table_name

LEFT()

返回某个被请求的文本域的左侧部分LEFT(str,len)
concat()把一堆字符串连起来CONCAT(str1,str2,...)
CONCAT_WS()字符串用指定字符连起来CONCAT_WS(separator,str1,str2,...)
YEAR()返回指定日期的年份数值SELECT YEAR(GETDATE())
SUBSTRING()字符串截取,pos从1开始,
空格不被计入
substring(str,pos, len)

substring_index()

字符串截取,sep分隔符,num的正负决定截取方向

substring_index(string,sep,num)

数学函数
ROUND()把数值字段舍入为指定的小数位数。(四舍五入)SELECT ROUND(column_name,decimals) FROM table_name
TRUNCATE(x,y)对操作数进行截取操作,结果保留小数点后面指定y位

CEIL(x), CEILING(x)

FLOOR(x)

不超最小,大于最小
RAND()返回一个随机浮点值v,范围在0到1之间(即0≤v≤1.0)参数可以填随机数种子seed
MOD(x,y)返回x被y除后的余数
时间函数
Now()返回当前时间和日期YYYY-MM-DD HH:MM:SS
TIMESTAMPDIFF()间隔的时间戳大小,返回intTIMESTAMPDIFF(YEAR,'2021-3-5','2021-5-4')
DATEDIFF()间隔的日期

Year()/Month()/Day()/

Hour()/Minute()/Second()

返回日期
TIME(expr)提取表达式expr 时间或日期时间的时间部分,并返回一个字符串

datatime和timestamp主要区别

timestamp会跟随设置的时区变化而变化,而datetime保存的是绝对值不会变化 

判断函数
IF()满足条件返回v1否则返回v2IF(expr, value1, v2)
IFNULL()value1不为空(null)则显示value1 ,否则显示value2IFNULL(value1,value2)
Case计算条件列表的表达式,并返回可能的结果之一case (expression)
when 判断 then value1
when 判断 then value2
else value3 end

案例:

SELECT COUNT(id) total_pv, 
COUNT(case when score is not null then 1 else null end) complete_pv, 
COUNT(DISTINCT IF(score is not null,exam_id,null)) complete_exam_cnt
FROM exam_record

SQL函数大全汇总_樱花花的博客-CSDN博客_sql函数

MySQL :: MySQL 5.7 Reference Manual :: 12.8 String Functions and Operators

5. SQL窗口函数OLAP函数(Online Anallytical Processing,联机分析处理)

窗口函数的基本语法如下:

<窗口函数> over (partition by <用于分组的列名>
                order by <用于排序的列名>)

<窗口函数>包括:

  1.  专用窗口函数,包括rank, dense_rank, row_number等专用窗口函数。
  2.  聚合函数,如sum. avg, count, max, min等

因为窗口函数是对where或者group by子句处理后的结果进行操作,所以窗口函数原则上只能写在select子句中

简单来说,窗口函数有以下功能:

  1. 同时具有分组和排序的功能
  2. 不减少原表的行数 (partition by 相比 group by)
排序函数 (括号内什么都不填)
rank()如果有并列名次的行,会占用下一名次的位置select *,
   rank() over (partition by 班级
                 order by 成绩 desc) as ranking
from 班级表
dense_rank()如果有并列名次的行,不占用下一名次的位置
row_number()不考虑并列名次的情况, 数字连续
取值函数
first_value()返回分区中的第一个记录值括号里填返回的值
last_value()返回分区中的最后一个记录值
nth_value()

返回窗口中第N个expr的值

expr可以是表达式,也可以是列名

nth_value(expr, n)
lag()

分区中位于当前行前n行的记录值

第三个参数是 超出记录窗口时的默认值

lag(expr, n)
lead()分区中位于当前行后n行的记录值lead(expr, n)

图示:

1、排名函数

2、聚合函数

窗口函数应用:

  • topN的万能模板:

select * from (select *, row_number() over (partition by 要分组的列名 order by 要排序的列名 desc) as ranking from 表名) as a where ranking = N;

  • “累计求和”问题的万能模板是:

select 列1,列2, sum(列名) over (order by 用于排序的列名) as 累计值的别名 from 表名;

6. SQL 正则表达式 

6.1 Like

MySQL可以通过 LIKE ...% 来进行模糊匹配。like匹配整个列,如果被匹配的文本仅在列值中出现,LIKE并不会找到它,相应的行也不会返回(当然,使用通配符除外)

6.2 regexp

REGEXP在列值内进行匹配。如果被匹配的匹配的文本在列值中出现,REGEXP将会找到它,相应的行将被返回

--匹配ok结尾的字段
SELECT name 
FROM user 
WHERE name REGEXP 'ok$'

6.3 not regexp

返回不匹配的列

6.4 regexp函数

regexp_instr():返回与正则表达式模式匹配的子字符串的起始索引

REGEXP_INSTR(expr, pattern[, position[, occurrence[, return_option[, match_type]]]])

regexp_like() :比较给定的字符串,如果字符串相同则返回,如果为真返回1,否则返回0

regexp_replace() :通过匹配字符来替换给定的字符串。

regexp_substr():从给定的字符串中返回子串

7. 公用表表达式(CTE)

Mysql8支持公用表表达式,包括非递归递归两种.

公用表表达式CTE允许使用命名的临时结果集,这是通过允许在SELECT语句和某些其他语句前面使用WITH子句来实现的.

  • 使用CTE的原因:不能在同一查询中两次引用派生表,那样的话,查询会根据派生表的引用次数计算两次或多次,这会引发严重的性能问题.使用CTE后,子查询只会计算一次
  • CTE和派生表区别:CTE可以引用其他的CTE,而派生查询不能引用其他派生查询

非递归CTE

--非递归CTE
WITH DERIVED AS (subquery) SELECT ... FROM derived, t1 ...


--派生查询不能引用其他派生查询:
    SELECT ... FROM (SELECT ... FROM ...) AS d1, (SELECT ... FROM d1 ...)AS d2...
--  ERROR: 1146 (42S02):Table 'db.d1' doesn't exist

--CTE可以引用其他的CTE:
    WITH d1 AS (SELECT ... FROM ...),d2 AS (SELECT ... FROM d1 ...)
    SELECT FROM d1,d2 ...

递归CTE

递归CTE是一种特殊的CTE,其子查询会引用自己的名字.WITH子句必须以WITH RECURSIVE开头.递归CTE子查询包括两部分:seed查询recursive查询,由UNION [ALL]或UNION DISTINCT分隔.

seed查询被执行一次以创建初始数据子集;recursive查询被重复执行以返回数据的子集,直到获得完整的结果集。当迭代不会生成任何新行时,递归会停止。

WITH RECURSIVE cte AS
(SELECT ... FROM table_name   /* seed SELECT */
UNION ALL
SELECT ... FROM cte, table_name)  /* "recursive" SELECT */
SELECT ... FROM cte;

实例:打印1——10数字

   mysql> WITH RECURSIVE cte(n) AS
          (SELECT 1 /* seed query */
          UNION ALL
          SELECT n+1 FROM cte WHERE n<10 /* recursive query */
          )
          SELECT * FROM cte;


三、事务Transactions

  • 四大特性(ACID)

事务特性描述
原子性(Atomicity)sql 语句的执行,要么全部成功,要么全部失败
一致性(Consistency)事务结束前后,数据 整体不变
隔离性(Isolation)多个事务独立运行,互不干扰
持久性(Durability)事务一旦提交,对数据的改变 永久有效

  • 隔离级别 Isolation level

隔离级别由低到高脏读不可重复读幻读数据库默认
读未提交 (Read Uncommitted)
读已提交 (Read Commited)×Oracle
重复读取(Repeatable Read)××Mysql
序列化 (Serializable)×××


    Lock: Nolock < ReadLock < RWLock < Mutex

  • 并发问题

事务读写对应最高隔离等级
脏读(Dirty Read)读取了修改但 "未提交" 的数据读未提交 (Read Uncommitted)
不可重复读
(Nonrepeatable Read)
读取过的数据, 再次读取出来发现值不同
偏向“update”
读已提交 (Read Commited)
幻读(Phantom Read)第 1 次和第 2 次读出来的记录数不一样
偏向“insert”和“delete”
重复读取(Repeatable Read)

  • 事务的结束

  1. '显示'结束:commit、rollback
  2. '隐式'结束:DDL、DCL(隐含了 commit)。强行退出 sql*plus,事务将自动回滚。


 四、触发器Trigger

  • 创建触发器

create [or replace] trigger 触发器名
   触发时间 {before | after}           -- view 中是 instead of
   触发事件 {insert | update | delete} -- dml、ddl、database
on 触发对象                            -- table、view、schema、database 
   触发频率 {for each row}            -- 行级触发器。默认:语句级触发器
   [follows 其它触发器名]              -- 多个触发器执行的 前后顺序
   [when 触发条件]
begin
   pl/sql 语句;
end;
/*
功能:after insert or update or delete 时,执行语句
命名:tr_aiud_student_info
*/
create or replace trigger scott.tr_aiud_student_info
   after insert or update or delete on scott.student_info
   for each row
begin
   case
      when inserting then
         dbms_output.put_line('插入成功!');
      when updating then
         dbms_output.put_line('更新成功!');
      when deleting then
         dbms_output.put_line('删除成功!');
      else
         dbms_output.put_line('无操作!');
   end case;
end;
/
  • 查询触发器

权限范围,由大到小:dba_* > all_* > user_*

select * from dba_triggers;
select * from all_triggers;
select * from user_triggers;
  • 删除触发器

drop trigger 触发器名;


select 'DROP TRIGGER ' || t.owner || '.' || t.trigger_name || ';' 删除
  from all_triggers t
 where t.owner = 'SCOTT'
   and t.table_name = 'STUDENT_INFO';
  • 触发器分类

DML 触发器,DDL触发器,Database触发器,insteadof触发器

图解|从根上彻底理解MySQL的索引 - 蝉沐风 - 博客园


五、PL/SQL (oracle数据库)

  • PL/SQL高级数据库程序设计语言(对Oracle数据库进行访问)集成于数据库服务器。
  • PL/SQL是对SQL语言存储过程语言的扩展
  • PL/SQL包括两部分,一部分是数据库引擎部分(数据库PL/SQL);另一部分是可嵌入到许多产品(如C语言,JAVA语言等)工具中的独立引擎(工具PL/SQL)。

PL/SQL 可用的SQL语句

  •  PL/SQL中只能用 SQL语句中的 DML 部分:INSERT,UPDATE,DELETE,SELECT INTO,COMMIT,ROLLBACK,SAVEPOINT
  • 如果要在PL/SQL中使用DDL(CREATE  table  )的话,只能以动态的方式来使用

PL/SQL块结构和组成元素

PL/SQL程序由三个块组成,即声明部分执行部分异常处理部分

PL/SQL的结构

DECLARE 

/* 声明部分: 在此声明PL/SQL用到的变量,类型及游标,以及局部的存储过程和函数 */

BEGIN

    /*  执行部分:  过程及SQL 语句  , 即程序的主要部分  */

EXCEPTION

   /* 执行异常部分: 错误处理  */

END;

其中 执行部分是必须的。

PL/SQL块可以分为三类:

  1. 无名块:动态构造,只能执行一次。
  2. 子程序:存储在数据库中的存储过程、函数及包等。当在数据库上建立好后可以在其它程序中调用它们。
  3. 触发器:当数据库发生操作时,会触发一些事件,从而自动执行相应的程序。

plsql基础教程(自学用) - 梦里仙人掌 - 博客园


六、Hive SQL (HQL)

HQL与SQL区别

  • HQL 不支持行级别的增、改、删,所有数据在加载时就已经确定,不可更改。
  • 不支持事务 Transaction。
  • 支持分区存储。

Hive 的 SQL 特点

  • Hive 更适合于分析复杂的数据集。SQL更适合于快速分析不太复杂的数据集。
  • Hive 执行时间长
  • 不支持等值连接,一般使用left join、right join 或者inner join替代
  • 不能智能识别concat(‘;’,key),只会将‘;’当做SQL结束符号
  • HiveQL中String类型的字段若是空(empty)字符串, 即长度为0, 那么对它进行IS NULL的判断结果是False,使用left join可以进行筛选行
  • 不支持 ‘< dt <’这种格式的范围查找,可以用dt in(”,”)或者between替代
  • 配置单元在HDFS中写入和查询数据。SQL需要多次读写。
  • SQL支持联机事务处理(OLTP)。配置单元不支持OLTP。

1. DDL语句

1.1 数据库操作

-- 创建数据库
create database if not exists hivetest;
create database if not exists hivetest location 'hdfs路径';  --指定数据库在HDFS上存放的位置
-- 显示数据库
show databases;
-- 查看数据库详情
desc database hivetest;
-- 切换当前数据库
use 目标数据库名称;
-- 删除空数据库
drop database if exists 库名;
drop database 库名 cascade; -- 如果数据库不为空,可以采用cascade命令,强制删除


七、MongoDB

1. 介绍

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。

  • Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
  • MongoDb 使用update()命令可以实现替换完成的文档(数据)或者一些指定的数据字段 。
  • Mongodb中的Map/reduce主要是用来对数据进行批量处理和聚合操作。
  • Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录,将key与value传给Reduce函数进行处理。
  • Map函数和Reduce函数是使用Javascript编写的,并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。
  • GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件。
  • MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。
  • MongoDB支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
  • MongoDB区分类型和大小写。
  • 文档中的键/值对是有序的。
  • MongoDB的文档不能有重复的键。

2. MongoDB和SQL

SQL术语/概念MongoDB术语/概念解释/说明
databasedatabase数据库
tablecollection数据库表/集合
rowdocument数据记录行/文档
columnfield数据字段/域
indexindex索引
table joins表连接,MongoDB不支持;但MongoDB可以嵌入文档
primary keyprimary key主键,MongoDB自动将_id字段设置为主键

3. MongoDB操作

3.1 数据库操作

创建数据库,如果存在则切换到指定数据库
use DATABASE_NAME

显示所有数据库
show dbs

删除当前数据库,默认为 test
db.dropDatabase()

3.2 集合(表)操作

创建集合,其中可选参数指定有关内存大小及索引的选项
db.createCollection(name, options)
集合只有在内容插入后才会真正创建

查看已有集合:
show collections 或 show tables

删除集合:
db.集合名.drop()

3.3 文档操作

插入文档:
db.COLLECTION_NAME.insert(document)  主键已经存在则会报错
或
db.collection.insertOne() 或 db.collection.replaceOne()  主键存在会更新,不存在会插入
插入一个多个文档:
db.collection.insertMany(
   [ <document 1> , <document 2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>
   }
)


项目实战

学籍管理系统-python实现+mysql - 知乎


踩坑汇总

1. MySql报错only_full_group_by

MySql从5.7版本开始默认开启only_full_group_by规则,规则核心原则如下,没有遵循原则的sql会被认为是不合法的sql

  1. order by后面的列必须是在select后面存在的
  2. select、having或order by后面存在的非聚合列必须全部在group by中存在

问题解决

  1. 第一种,修改sql使其遵守only_full_group_by规则(费时间)
  2. 第二种,将MySql的版本降到5.7以下(不推荐)
  3. 第三种,关闭only_full_group_by规则

2. 同一Select语句使用别名运算报错

处于同级一样从上一个虚拟表中取值(参考sql执行顺序),故找不到对应列

3. sql窗口函数last_value取的值不是分组中最后一个的值

因为默认是取到分组(可选)第一项到当前行的, 即

last_value()默认统计范围是 rows between unbounded preceding and current row

如果Order的值变化了,基本上也就是当前行的值了,如果没有变化就取相同Order系列中的最后一项。

问题解决

  1. 第一种,添加 rows between unbounded preceding and unbounded following
last_value(col) over (order by col rows between unbounded preceding and unbounded following)
  1. 第二种,改用 first_value然后desc排序

4. mysql的utf8编码不能支持表情符号

解决方法:更改 MySQL 数据库的编码为 UTF8MB4。utf8mb4 编码是 utf8 编码的超集,兼容 utf8,并且能存储 4 字节的表情字符。

需要修改 MySQL 配置文件

修改mysql配置文件myf(Linux系统),Windows 系统为 my.ini。
myf一般在etc/mysql/myf位置。找到后请在以下三部分里添加如下内容: 

[client] 
default-character-set = utf8mb4

[mysql] 
default-character-set = utf8mb4

[mysqld] 
character-set-client-handshake = FALSE 
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci 
init_connect='SET NAMES utf8mb4'

更改数据库和已经建好的表也转换成 utf8mb4

更改数据库编码:ALTER DATABASE DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

更改表编码:ALTER TABLE TABLE_NAME CONVERT TO CHARACTER SET utf8mb4 COLLATEutf8mb4_general_ci; 

Ps:如有必要,还可以更改列的编码。


 References

Oracle 事务详解(transaction)_鱼丸丶粗面的博客-CSDN博客_oracle事务

Oracle 触发器详解(trigger)_鱼丸丶粗面的博客-CSDN博客_oracle触发器详解

MySql报错only_full_group_by的解决办法 - 知乎

通俗易懂的学会:SQL窗口函数 - 知乎

Hive(总)看完这篇,别说你不会Hive!_子清.的博客-CSDN博客_hive

一文学完所有的Hive Sql(两万字最全详解)_五分钟学大数据的博客-CSDN博客_hive sql

Mysql8之公用表表达式(CTE) - 知乎

更多推荐

各种DBMS和Sql语言