这是我参与更文挑战的第5天,活动详情查看: 更文挑战
数据库
数据库(Database DB)是将大量数据保存起来,通过计算机加工而成的可以进行高效访问的数据集合。
用来管理数据库的计算机系统称为数据库管理系统(Database Management System
,DBMS)。
数据库和数据库管理系统经常被混淆。
DBMS的种类
DBMS主要通过数据的保存格式(数据库的种类)来进行分类。主要有5种类型。
- 层次数据库(
Hierarchical Database
, HDB)
最古老的数据库之一,它把数据通过层次结构(树形结构)的方式表现出来。层次数据库曾是数据库的主流,随着关系数据库的出现和普及,已经很少使用了。
- 关系数据库(
Relational Database
, RDB)
关系数据库是现在应用最广泛的数据库。关系数据库在1969年诞生,采用由行和列组成的二维表来管理数据,同时使用专门的SQL(Structured Query Language
,结构化查询语言)对数据进行操作。
这种类型的DBMS称为关系数据库管理系统(Relational Database Management System
, RDBMS)。常见的有OracIe Database、SQL Server、DB2、PostgreSQL、MySQL
- 面向对象数据库(
Object Oriented Database
, OODB)
借鉴于编程语言当中面向对象语言的概念。把数据以及对数据的操作集合起来以对象为单位进行管理,因此得名。面向对象数据库就是用来保存这些对象的数据库。
- XML数据库(
XML Database
, XMLDB)
XML数据库可以对XML形式的大量数据进行高速处理
- 键值存储系统(
Key-Value Store
, KVS)
是一种单纯用来保存查询所使用的主键(Key)和值(Value)的组合的数据库。即类似编程中的json格式,或者关联数组或者散列(hash)。近年来,随着键值存储系统被应用到Google等需要对大量数据进行超高速查询的Web服务当中,它正逐渐为人们所关注。
数据库和表的结构
RDBMS通常采用客户端/服务器类型(C/S类型)的系统结构
服务器指的是用来接收其他程序发出的请求,并对该请求进行相应处理的程序(软件),或者是安装了此类程序的设备(计算机)。RDBMS就是一种服务器,它从保存在硬盘上的数据库中读取数据并返回,或者更改数据。
对应地,向服务器发出请求的程序(软件),或者是安装了该程序的设备(计算机)称为客户端。多个客户端可以同时对同一个数据库进行读写操作。
用来管理数据的二维表在关系数据库中简称为表,它存储在由RDBMS管理的数据库中
表(table):某种特定类型数据的结构化清单。在表中的数据是同一种类型的数据或清单。即某一类数据的集合
根据SQL语句的内容返回的数据同样必须是二维表的形式(关系数据库的特征之一)。
- 表的列
column
(垂直方向)称为字段,表示保存在表中的数据项目; - 表的行
row
(水平方向)称为记录,表示一条数据。
关系数据库必须以行为单位进行数据读写
模式(
schema
)是用来描述数据库中特定的一些表或者整个数据库,有关数据存储、数据特性、以及表关系和布局等的信息。也可以翻译为”架构”。
数据类型
创建表时指定的列名的右边,会紧跟该列的数据类型。所有列都必须指定数据类型。
数据类型表示数据的种类,如数字型(INTEGER
)、字符型(CHAR
,CHARACTER[字符]的缩写,即存储字符串)和日期型(DATE
)。
每一列只能存储与该列数据类型相同的数据。
- 关于CHAR和VARCHAR类型
CHAR类型的列中存储的是定长字符串。定长字符串,就是当列中存储的字符串长度达不到最大长度的时候,使用半角空格进行补足,即列出存储的是固定长度的字符串。
VARCHAR类型的列中存储的是可变长字符串。当存储的字符串没有达到VARCHAR指定的最大长度时,仍以原字符串进行存储。相对char更灵活,且存储空间较小。
OracIe中使用的是
VARCHAR2
型(也有VARCHAR,但不推荐使用)OracIe中的DATE型还包含时分秒。
- 约束
约束是对列中存储的数据进行限制或者追加条件的功能。
比如NOT NULL
非空约束、PRIMARY KEY
主键约束。
表中每一行都应该有一列(或几列)可以唯一标识自己,并将该列(或几列)设置为主键。原则上,每个表都有主键。
主键列中的值不允许修改或更新。
键是在指定特定数据时使用的列的组合。
SQL
SQL概要
SQL是一种专门用来操作数据库的语言。
国际标准化组织(ISO)为SQL制定了相应的标准,以此为基准的SQL称为标准SQL,使用标准SQL写的语句可以在各个RDBMS通用。
标准SQL由ANSI标准委员会管理,从而称为
ANSI SQL
。
SQL用关键字、表名、列名等组合成SQL语句来描述操作的内容。
关键字是指事先定义好的有着特殊含义或使用方法的单词,用来组成SQL语句。它是SQL语言中的保留字。
reserved keyword
保留关键字
SQL语句分类:DDL、DML、DCL
根据RDBMS执行指令种类的不同,SQL语句可分为三类:
DDL
(Data Definition Language
,数据定义语言)用来创建或者删除存储数据用的数据库以及数据库中的表等对象。DDL包含以下几种指令。
CREATE:创建数据库和表等对象;
DROP:删除数据库和表等对象;
ALTER:修改数据库和表等对象的结构
DML
(Data Manipulation Language
,数据操作语言)用来查询或者变更表中的记录。DML包含以下几种。
SELECT:查询表中的数据;
INSERT:向表中插入新数据;
UPDATE:更新表中的数据;
DELETE:删除表中的数据
此处还可以细分为:数据查询语言(
DQL
,Data Query Language
——SELECT
)和数据操作语言(DML
——INSERT
、UPDATE
、DELETE
)
DCL
(Data Control Language
,数据控制语言)用来确认或者取消对数据库中的数据进行的变更,以及设定RDBMS的用户是否有权限操作数据库中的对象。包含以下几种。
COMMIT:确认对数据库中的数据进行的变更;
ROLLBACK:取消对数据库中的数据进行的变更;
GRANT:赋予用户操作权限;
REVOKE:取消用户的操作权限;
SQL语句规则
SQL语句基本规则:
- SQL语句要以分号(;)结尾。大多数(不是所有)DBMS在执行单条语句时可以不加分号。似乎SQL Server是例外,其语句可以不使用分号,多条语句使用空格或回车分隔即可,但仍推荐使用分号。
- SQL语句不区分大小写。关键字、表名、列名等不区分大小写。具体的值肯定要区分大小写,但表名、列名等却(大多)可以通过DBMS的设置实现区分大小写。
- 常数的书写方式是固定的。字符串和日期常数使用单引号(’)括起来,数字直接书写即可。
- 单词需要用半角空格或者换行来分隔。
ANSI(美国国家标准协会)或ISO(国际标准化组织)等会隔几年修订SQL的标准(修订语法、追加功能)。以这些标准为基准的SQL就是标准SQL。
但是不同的数据库管理系统各自有着只能在自己特定RDBMS中使用的特殊SQL语句
关于关键字、非常规的标识符
标识符(identifier
)指的是数据库对象的名字。比如服务器、数据库、以及表、视图、列、索引、触发器、约束、存储过程等数据库对象,任何事物都可以有一个标识符,即有一个名字标识其自身。
标识符的规则一般都是只能包含字母、数字、下划线(_)。大多数编程语言的标识符规则都是如此。
在数据库中称为常规标识符(Regular identifier
),或规则标识符。
但是如果标识符中包含关键字,或空格等字符时,必须要使用界定标识符(Delimited identifier
)的形式,将其引起来,才能使用。
比如创建一个名为table
或select
的表,直接创建将会报语法错误,因为这是保留关键字。
在SQL Server中,界定标识符,需要用双引号"
或方括号[]
包含起来;
PostgreSQL中,界定标识符,用双引号"
包含起来;
MySQL/MariaDB中,界定标识符,用`(反引号,键盘上左上角和波浪线~
一块的符号)包含起来。
注:实际测试在PostgreSQL的psql命令行里使用双线号创建受限标识符的数据库时无效,即不报错也没创建成功。但在pgAdmin4中能成功创建。
-- PostgreSQL | SQL Server
create table "select a"(
id integer
)
-- SQL Server
create table [select a](
id integer
)
-- MySQL/MariaDB
create table `select a`(
id integer
)
复制代码
常见DDL操作
创建数据库和表
使用psql登陆PostgreSQL,创建数据库shop
CREATE DATABASE shop;
复制代码
删除数据库的方法也很简单
DROP DATABASE shop; 复制代码
CREATE TABLE
创建表的语句如下:
CREATE TABLE <表名>
(
<列名1> <数据类型> <该列约束>,
<列名2> <数据类型> <该列约束>,
.
.
.
<表的约束1>,<表的约束2>,...
);
复制代码
创建表时每一列的列名和数据类型必须要指定,约束可以直接在列类型后指定,也可以在语句末尾设置。
只有字母、数字、下划线(_)可以作为数据库、表和列的名称,且不能以数字开头
如下,创建商品表(Product):
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 Server、MySQL/MariaDB中,整型
integer
一般都用int
表示。PostgreSQL通常使用integer
。这几种DBMS都支持使用integer
和int
由于特殊的历史原因,在MySQL/Mariadb中创建表时,最好指定编码格式为
utf8mb4
。尤其是需要用到UTF-8
编码的汉字或表情符号时。如下,否则插入中文内容时会报错。
CREATE TABLE `Product` ( `product_id` char(4) COLLATE utf8mb4_unicode_ci NOT NULL, `product_name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, `product_type` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL, `sale_price` int(11) DEFAULT NULL, `purchase_price` int(11) DEFAULT NULL, `regist_date` date DEFAULT NULL, PRIMARY KEY (`product_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 复制代码
默认的
CHARSET=latin1
。比较的做法是:通过修改MySQL/Mariadb的配置文件,设置字符编码为
utf8mb4
,这样就不用在每个建表语句(包括语句的列)上指定编码。
Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。
ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。
Latin1主要针对欧洲地区的文字的编码扩展。
ISO-8859-1
是8位(单字节)编码的国际标准。
删除表
DROP TABLE <表名>;
复制代码
更新表和字段
更新表定义
1. 添加列
ALTER TABLE <表名> ADD COLUMN <列的定义>;
复制代码
OracIe
和SQL Server
中不用写COLUMN:
ALTER TABLE <表名> ADD <列的定义>; 复制代码
OracIe中同时添加多列的时候可以添加如下括号:
ALTER TABLE <表名> ADD (<列的定义>,<列的定义>);
。
SQL Server等则不需要添加括号,各个列定义逗号,
分隔即可。
比如Product表添加一列product_name_pinyin
:
-- PostgreSQL | MySQL | DB2
ALTER TABLE Product ADD COLUMN product_name_pinyin VARCHAR(100);
-- SQL Server
ALTER TABLE Product ADD product_name_pinyin VARCHAR(100);
-- Oracle
ALTER TABLE Product ADD (product_name_pinyin VARCHAR(100));
复制代码
2. 删除列
ALTER TABLE <表名> DROP COLUMN <列名>;
复制代码
Oracle中不用写COLUMN,
ALTER TABLE <表名> DROP <列名>;
。删除多个列时,使用括号。
如下,删除列product_name_pinyin
-- SQL Server | DB2 | PostgreSQL | MySQL
ALTER TABLE Product DROP COLUMN product_name_pinyin;
-- Oracle
ALTER TABLE Product DROP (product_name_pinyin);
复制代码
3. 修改字段名称
修改列名可以使用如下语句
-- PostgreSQL
ALTER TABLE Product RENAME purchase_price TO purchase_price1;
-- SQL Server
EXEC sp_rename '表名.[字段旧名]', '字段新名' , 'COLUMN';
-- MySQL/MariaDB 使用change修改字段名称,新名称必须指定字段类型,否则报错,即相当于重建了一个列。 column关键字可有可无
-- alter table tab_name change [column] old_name new_name DATETYPE [first|after col_name]
alter table Product change column purchase_price purchase_price1 int(11);
复制代码
MySQL/MariaDB中使用change修改字段名称,新名称必须指定字段类型,否则报错,即相当于重建了一个列。如果想实现仅重命名,需要将旧字段有关的类型、约束等前部赋给新字段名
4. 修改字段类型
-- PostgreSQL
ALTER TABLE Product ALTER COLUMN regist_date TYPE timestamp; -- 等同 timestamp without time zone
-- Oracle | MySQL/MariaDB modify用来修改列的定义,不仅仅是类型
alter table Product modify regist_date timestamp;
-- MySQL/MariaDB modify column关键字可有可无
alter table Product modify column regist_date date;
-- SQL Server
alter table Product alter column regist_date datetime null;
-- MySQL/MariaDB 还可以使用change修改字段类型。因为是重建列,不推荐
alter table Product change [column] regist_date regist_date timestamp;
复制代码
实际测试,使用MySQL/MariaDB中修改字段类型时,默认约束也会变更。其他DBMS为全部测试,但实际修改字段类型时,一定要在测试数据库中提前测试好。
还有一个**
ALTER COLUMN
** 子句,但是只能用来设置和移除默认值。
对于MySQL/MariaDB,使用MODIFY或CHANGE修改表的结构,它要执行的操作就是新建一张满足需求的表,再插入数据,如果这张表的数据量特别大时,索引很多,内存又不足等情况下,这样的修改或许会花费几个小时甚至几天。因此在大表情况下,尽量不要执行MODIFY或CHANGE命令修改字段。有一种非官方推荐的方法,通过移动
.frm
文件实现。具体查看MySQL中MODIFY|CHANGE|ALTER COLUMN的区别
5. 修改表名
如果发现表名写错了,或者想要修改表名,可以使用下面语句
-- PostgreSQL | Oracle | MySQL
ALTER TABLE Product RENAME TO Product1;
-- SQL Server
sp_rename 'Product','Product1';
-- MySQL | DB2
RENAME TABLE Product to Product1;
-- MySQL修改表的语句,[to|as]可以省略。 alter table tbl_name rename[to|as] new_tbl_name
复制代码
标准SQL中并没有RENAME
DML操作:插入数据
INSERT INTO <表名> VALUES (value1, value2 ,...);
-- 或
INSERT INTO <表名>(col1,col2,...) VALUES (value1, value2 ,...);
复制代码
如下,向Product表中插入数据:
--SQL Server PostgreSQL
-- DML:插入数据
BEGIN TRANSACTION; -- MySQL为 START TRANSACTION; -- Oracle DB2 不需要添加此行,删除即可
INSERT INTO Product VALUES ('0001', 'T恤' ,'衣服', 1000, 500, '2009-09-20');
INSERT INTO Product VALUES ('0002', '打孔器', '办公用品', 500, 320, '2009-09-11');
INSERT INTO Product VALUES ('0003', '运动T恤', '衣服', 4000, 2800, NULL);
INSERT INTO Product VALUES ('0004', '菜刀', '厨房用具', 3000, 2800, '2009-09-20');
INSERT INTO Product VALUES ('0005', '高压锅', '厨房用具', 6800, 5000, '2009-01-15');
INSERT INTO Product VALUES ('0006', '叉子', '厨房用具', 500, NULL, '2009-09-20'),
('0007', '擦菜板', '厨房用具', 880, 790, '2008-04-28'),
('0008', '圆珠笔', '办公用品', 100, NULL, '2009-11-11');
COMMIT;
复制代码
注:插入大量的多个行时推荐使用多行插入的方式,速度会快很多,后续会介绍