注册
SQL基础概念
技术分享/ 文章详情 /

SQL基础概念

青空 2026/07/31 150 0 0

SQL:

是一种关系型数据库,关系型的体现是其以表格形式组织(逻辑结构)数据,表和表之间通过关系建立关联,比如一个学生表里会有学院号,就能和学院表产生关联,还可以声明其为外键

而非关系型数据库NoSQL包括MongoDB、Redis之类的

ACID

是关系型数据库事务的四个核心特性,事务是一组要么全部成功、要么全部回滚的操作(原子性)

  • A原子性(Atmoicity)
  • C一致性(Consistency):事务前后数据必须满足所有约束规则,不能留下破坏规则的数据,比如主键约束、外键关联存在、字段类型正确等
  • I隔离型(Isolation):多个事务同时执行时互不干扰,主要就是不能因为并发操作产生脏读之类的问题,这里涉及隔离级别的问题
  • D持久性(Durability):事务提交后不会因为断电消失

原子性通过回滚日志Undo Log实现,在修改数据前先在Undo Log中记录修改前的旧值,使得如果事务崩溃或主动回滚时可以恢复,如果事务成功提交就将相应的Undo Log标记为可清理

一致性由应用层和数据库共同写作,通过约束(主键、外键、唯一键、检查约束等)和触发器防止写入非法数据,并借助事务的原子性、隔离性和持久性来间接维护一致性,在事务执行过程中任何违反约束的操作都会被阻止并回滚,保证数据始终从一种有效状态转变为另一种有效状态

隔离性通过锁机制和多版本并发控制MVCC实现,有四种隔离级别

持久性通过重做日志Redo和双写缓冲区实现,遵循WAL(Write Ahead Log)原则,事务提交前其对应的Redo日志必须强制写入磁盘,而数据盘可以延迟写入,双写缓冲区用于解决页断裂问题,当数据页写入磁盘时若系统发生崩溃,可能只写了一半,双写会先在磁盘预留区域完整写入该页副本,再写入实际位置

四种隔离级别,

先说可能存在的问题:

  • 脏读:读到了未提交的数据,比如其他事务在提交前修改/撤回了这个数据,就读到了根本不存在的数据
  • 不可重复读:同一个事务读两次,两次结果可能不同
  • 幻读:两次查询得到的行数可能变化

隔离级别大概就是说用性能换准确的四种级别

  • 读未提交:能读取还没提交(commit)的事务数据,可能导致脏读、不可重复读、幻读
  • 读已提交:只能读取到已提交事务的数据(说是postgreSQL和Oracle的默认级别),但仍然可能导致不可重复读和幻读(比如自己先开始,先读了一次,然后其他事务进行了修改/插入/删除操作并提交)
  • 可重复读:要求同一事务内多次读同一行结果始终一致,哪怕其他事务已经提交了这一行更新的值,但没有解决幻读问题
  • 串行化:字面意思,事务一个个执行,完全没有并发(或者说是加了锁的并发)和并行,性能显而易见地差

脏读和不可重复读的区别在于是否读到了一个从未被提交的值,脏读可能读到一个从未被提交的值(A还没提交B就读了一下,后面A又撤回了这个修改),不可重复读可能先读了一次,其他事务修改并提交,然后又读了一次,使得两次读到的结果不一样

各种语句

  • 数据定义
    • CREATE 创建数据库对象
    • DROP 删除库对象
    • ALTER 改库对象,比如对一个表新增一列或去掉一列
  • 数据操纵
    • INSERT 向表中插入数据
    • UPDATE 更新表中数据
    • DELETE 删除表中(某几行)数据
  • 数据控制
    • GRANT 授予权限
    • REVOKE 解除权限
  • 数据查询 SELECT

基本对象

  • 表空间tablespace是表的物理结构(操作系统这一块)
  • 用户user
  • 模式schema类似于C++的namespace,是数据库的逻辑命名空间,用于防止同名对象冲突
  • 视图view是一种虚拟的表
  • 列column
  • 存储过程procedure是一种不要求是否有返回值的存储函数
  • 存储函数function是一种预制好的SQL语句,并且必须有(且只有)一个返回值
  • 触发器trigger是在insert/update/delete时自动触发的一段代码,用于校验、记录之类的
  • 序列sequence相当于所有表共用版本的标识identity
  • 索引index用于加快查询(where、order by、join on),但可能会导致插入速度下降
  • 数据字典dictionary存储库的逻辑结构定义

不同类型

  • 字符串
    • char(n)定长字符串
    • varchar(n)变长字符串
    • text长文本
  • 数值
    • 整形bigint、int、smallint、tinyint,分别是8、4、2、1字节
    • 精确小数decimal(p,s)、numeric(p,s),需要同时指定总位数p和小数位数s
    • 近似小数float、double
  • 日期时间:date年月日、time时分秒、datetime和timestamp年月日时分秒
  • 二进制blob
  • 二进制位bit,只有0、1或null三种值
  • 布尔boolean、bool

字段属性

  • 数据类型(如上所述)
  • 缺省值(默认值)DEFAULT xxx
  • 能否为空
    • 可为空 NULL
    • 非空 NOT NULL
  • 标识 IDENTITY,自动编号,只能用于数值类型列
  • 约束
    • 唯一 UNIQUE
    • 主键 PRIMARY KEY,唯一且非空
    • 外键 FOREIGN KEY,引用其他表的主键或标识

语法要素

  • 属性词predicates,比如distinct(去重)、top/limit(选前n条)
  • 条件子句clause,比如select、from、where、group by之类的
  • 运算符operator,比如=<>AND OR NOT IN BETWEEN LIKE
  • 操作数operation,上面这个operation对谁用,比如WHERE age>20里面的age
  • 函数function,比如COUNT()统计行数、SUM(列名)求和、MAX(列)最大值、MIN(列)最小值、AVG(列)平均值、以及字符串函数、数值函数、日期函数、条件函数、类型转换函数等
  • SQL语句statement,整条SQL语句,用;结尾
  • 基本格式是:命令+条件子句
select(命令) 哪些列 from(命令) 哪些表 where(命令) 条件

PPT的例子不太好理解,简化一下:

select [可选属性词] 哪些列(还可以用 as 设置别名) from 哪些表 怎么 join on(有内连接、左连接、右连接、全连接、CROSS连接,还有一种不同的分类维度能分出自连接) where 怎么对行进行筛选,在分组之前 group by 怎么分组 having(基本和 group by 配套) 怎么对组进行筛选(在分组之后) order by 怎么排序(默认是 ASC 升序,还有一种是 DESC 降序)

执行顺序:

from join where group by having select order by

排序、主键、索引

PPT上说“SQL表数据没有内在的顺序”,是说select展示时的顺序可能是插入顺序或索引扫描顺序等

在MySQL中存储表时会以主键的大小用B+树进行存储,如果没有显式声明主键,数据库自己会隐式声明一个主键ROW_ID

在MySQL中,如果设置主键索引/聚簇索引,会以此使用B+树存储表,叶子节点存储的即为行数据本身(而不是其指针)

达梦数据库的主键和聚簇索引可以分离,默认情况下主键只是一个唯一且非空约束、普通索引,物理存储以隐藏的ROWID组织

关于删除

drop删库/表(无法恢复)

delete删除指定行

truncate清空表(且不记录删除了什么,无法找回,也因此更快)

建立索引

有聚簇索引clustered和非聚簇索引,聚簇索引的数据就是索引,叶子节点存放的就是数据,非聚簇索引的索引是目录,其叶子节点存放的是指向数据的指针

每个表只能有一个聚簇索引,因为一个表只能以一种物理顺序存放

CREATE INDEX MYCOLUMN_INDEX ON MYTABLE (MYCLUMN);

删除索引

DROP INDEX MYCOLUMN_INDEX;

建立聚簇索引(MySQL不支持,达梦支持

CREATE CLUSTERED INDEX MYCOLUMN_CLUST_INDEX ON MYTABLE(MYCOLUMN);

建立唯一索引

CREATE UNIQUE CLUSTERED INDEX MYCLUMN_CINDEX ON MYTABLE(MYCOLUMN);

建立复合索引

CREATE INDEX NAME_INDEX ON USERNAME(FIRSTNAME,LASTNAME);

运算符

= > < >= <=无需解释

<>不等于

LIKE匹配,%代替任何字符串(0~inf个字符)、_匹配任意一个字符

非标准:[]匹配里面的任意单个字符、[^]匹配不在里面的任意单个字符、-配合[]匹配一个范围内的任意单个字符

别名(as是可加可不加的)

SELECT A1.STORE_NAME AS "STORE",SUM(SALES) AS "TOTAL SALES" FROM STORE_INFORMATION AS A1 GROUP BY A1.STORE_NAME;

子查询

SELECT COLUMN1 FROM TABLE1 WHERE EXISTS ( SELECT COLUMN1 FROM TABLE2 WHERE TABLE1.COLUMN1 = TABLE2.COLUMN1 );

联合查询UNION

SELECT * FROM 学生信息 UNION SELECT * FROM 学生信息; SELECT * FROM 学生信息 UNION ALL SELECT * FROM 学生信息;

union相比union all会去重,相当于自带distinct

视图

是一个虚拟的表,但行为类似于真实的表,在插入是就是对其基表进行插入,但不是所有视图都能插入

CREATE VIEW 视图名 AS SELECT 哪些列 FROM 哪些表 什么条件; 例子: CREATE VIEW V_Student AS SELECT Name, Age FROM Student;

不能插入/更新的视图:

定义有distinct、group by、union和union all,以及某些情况的子查询、多表连接

控制事务

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

提交commit

在没有声明事务(begin、start)时,达梦默认会自动commit,如果是事务则需要手动commit

SQL入门在线实操

查看数据库运行状态

SELECT status$ as 状态 FROM v$instance;

查看数据库版本

SELECT banner as 版本信息 FROM v$version;

创建用户

CREATE USER DM IDENTIFIED BY "dameng123";

用户名为DM,密码为dameng123

授权,给DM授予RESOURCE角色

GRANT RESOURCE TO DM;

给DM授权 可以select查看dmhr库的employee表

GRANT SELECT ON dmhr.employee TO DM;

给DM授权 可以select查看dmhr库的department表

GRANT SELECT ON dmhr.department TO DM;

从dba_users字典表查看DM的信息,包括用户名、账号状态、创建时间

SELECT username,account_status,created FROM dba_users WHERE username='DM';

切换用户,/后面是密码

conn DM/dameng123;

返回当前登录(使用)的用户

SELECT user FROM DUAL;

创建表employee,包括id、name、daye、salary、d_id列

CREATE TABLE employee ( employee_id INTEGER, employee_name VARCHAR2(20) NOT NULL, hire_date DATE, salary INTEGER, department_id INTEGER NOT NULL );

创建表department,包括d_id、d_name列

CREATE TABLE department ( department_id INTEGER PRIMARY KEY, department_name VARCHAR(30) NOT NULL );

给表的列添加约束

  • 非空约束NOT NULL:
ALTER TABLE employee MODIFY( hire_date not null);
  • 主键约束PRIMARY KEY(非空且唯一):
ALTER TABLE employee ADD constraint pk_empid PRIMARY KEY(employee_id);
  • 外键约束FOREIGN KEY:
ALTER TABLE employee ADD constraint fk_dept FOREIGN KEY (department_id) REFERENCES department (department_id);

查看表的主键和外键

SELECT table_name, constraint_name, constraint_type FROM all_constraints WHERE owner='DM' AND able_name='EMPLOYEE';

插入数据

INSERT INTO department VALUES(666, '数据库产品中心');
INSERT INTO employee VALUES (9999, '王达梦','2008-05-30 00:00:00', 30000, 666);

提交事务

INSERT INTO employee VALUES (9999, '王达梦','2008-05-30 00:00:00', 30000, 666);

由于employee表和department表存在主外键约束,所以要先插入department表中的对应数据,有d_id为666的数据,才能使employee表中能插入d_id为666的员工。类比一下就是必须先存在这个部门,才能把人划分到这个部门里

修改(更新UPDATE)数据

UPDATE employee SET salary='35000' WHERE employee_id=9999;

修改完之后提交事务

commit;

查看是否更新成功

SELECT salary,employee_id FROM employee;

删除表数据(清空该表所有行)

DELETE FROM employee;

删除表里符合条件的行

DELETE FROM department WHERE department_id=666;

提交事务

commit;

验证是否删除成功

SELECT * FROM employee;

批量插入

CREATE TABLE t1 AS SELECT rownum AS id, trunc(dbms_random.value(0, 100)) AS random_id, dbms_random.string('x', 20) AS random_string FROM dual connect BY level <= 100000;

查看有多少行

SELECT COUNT(*) FROM t1;

使用ORDER BY进行选择排序

SELECT * FROM t1 where rownum<5 ORDER BY id DESC;

DESC表明其是降序排序,默认情况下排序是ASC升序排序

INSERT INTO department (department_id, department_name) SELECT department_id, department_name FROM dmhr.department;
评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服