《数据库基础语法》1. 在SQL的世界里一切都是关系
楔子
SQL 是每个开发人员都应该掌握的,很多人可能觉得 SQL 没啥大不了的,但是说真的,SQL要是写好了,是很厉害的。下面我们来从零开始学习SQL。
基本概念
正如 Linux 中一切皆文件,Python中一切皆对象,SQL(Structured Query Language,结构化查询语言)中可以把一切都看成是关系。我们来看看一些概念:
关系型数据库:
关系型数据库(Relational database)是指基于关系模型的数据库。关系模型由关系数据结构、关系操作集合、关系完整性约束三部分组成。
数据结构:
关系模型中,用于存储数据的逻辑结构称为 关系(Relation);对于使用者而言,关系就是 二维表(Table)。
以下是一张员工信息表,知道 Excel 的人肯定会很熟悉,因为它和 Excel 的结构非常类似,由 行(Row)和 列(Column)组成。
关系型数据库中还有一些常见的概念:
关系,也称为表,用于表示现实世界中的实体(Entity)或者实体之间的联系(Relationship)。举例来说,一个公司的员工、部门和职位都是实体,分别对应员工信息表、部门信息表和职位信息表;销售的产品和订单都是实体,同时它们之间存在联系,对应订单明细表。
行,也称为记录(Record),代表了关系中的单个实体。上图中pk为 8 的数据行存储了id 为 "01010009350" 的相关信息。关系(表)可以看作是由行组成的集合。
列,也称为字段(Field),表示实体的某个属性。上图中的第二列包含了员工的id。表中的每个列都有一个对应的数据类型,常见的数据类型包括字符类型、数字类型、日期时间类型等。
操作集合:
有了关系结构之后,就需要定义基于关系的数据操作。
常见的数据操作包括:增加(Create)、查询(Retrieve)、更新(Update)、以及删除(Delete),它们统称为:增删改查(CRUD)
其中,使用最多、也最复杂的操作就是查询,具体来说包括:选择(Selection)、投影(Projection)、并集(Union)、交集(Intersection)、差集(Exception)以及 笛卡尔积(Cartesian product)等等,我们后面会介绍如何使用 SQL 语句完成以上各种数据操作。
为了维护数据的完整性或者满足业务需求,关系模型还定义了完整性约束。
完整性约束:
关系模型中定义了三种完整性约束:实体完整性、参照完整性、以及 用户定义完整性。
实体完整性是指表的主键字段不能为空。现实中的每个实体都具有唯一性,比如每个人都有唯一的身份证号;在关系数据库中,这种唯一标识每一行数据的字段称为主键(Primary Key),主键字段不能为空。每个表可以有且只能有一个主键。但是一个主键不一定只对应一个字段,也可以是多个字段共同组合成联合主键,但它仍然是一个主键
参照完整性是指外键参照的完整性。外键(Foreign Key)代表了两个表之间的关联关系,比如员工属于某个部门;因此员工表中存在部门编号字段,引用了部门表中的部门编号字段。对于外键引用,被引用的数据必须存在,员工不可能属于一个不存在的部门;删除某个部门之前,也需要对部门中的员工进行相应的处理。
用户定义完整性是指基于业务需要自定义的约束。非空约束(NOT NULL)确保了相应的字段不会出现空值,例如员工一定要有姓名;唯一约束(UNIQUE)用于确保字段中的值不会重复,每个员工的电子邮箱必须唯一;检查约束(CHECK)可以定义更多的业务规则。例如,薪水必须大于 0 ,字符必须大写等;默认值(DEFAULT)用于向字段中插入默认的数据。
另外我们说的 SQL 其实是一个工业标准,或者说它指的是操作数据库中的二维表时所使用的语言,而不同种类的关系型数据库的 SQL 也是不同的,但是它们大致都是一样的。常见的数据库一般有 MySQL、Oracle、PostgreSQL、SQL Server,我们后续介绍的 SQL,这四种数据库都支持,如果不支持,我们单独指出来。
SQL 的语法特性
SQL 是一种声明性的编程语言,语法接近于自然语言(英语)。通过几个简单的英文单词,例如 SELECT、INSERT、UPDATE、CREATE、DROP 等,来完成大部分的数据库操作。以下是一个简单的查询示例,这里只是提前感受一下 SQL,具体的语法细节我们后面会说:
SELECT emp_id, emp_name, salary
FROM employee
WHERE salary > 10000
ORDER BY emp_id;
即使没有学过 SQL 语句,但只要知道几个单词的意思,就能明白该语句的作用。它查询员工表(employee)中月薪(salary)大于 10000 的员工,返回工号、姓名以及月薪,并且按照工号进行排序。可以看出,SQL 语句非常简单直观。
以上查询中的 SELECT、FROM 等称为关键字(也称为子句),一般大写;表名、列名等内容一般小写;分号表示语句的结束。其实 SQL 语句的关键字、以及内置的函数是不区分大小写的,但是遵循一定的规则可以让代码更容易阅读。
对于 SQL 语句而言,它所操作的对象是一个集合(表),操作的结果也是一个集合(表)。例如以下查询:
SELECT emp_id, emp_name, salary
FROM employee;
其中 employee 是一个表,它是该语句查询的对象;同时,查询的结果也是一个表。所以,我们可以继续扩展该查询:
SELECT emp_id, emp_name, salary
FROM (
SELECT emp_id, emp_name, salary
FROM employee
) as t;
我们将括号中的查询结果(取名为 t)作为输入值,传递给了外面的查询,最终整个语句的结果仍然是一个表。这种嵌套在其他语句中的查询就是子查询(Subquery),后续我们会详细介绍。
总之,SQL 中的查询可以完成各种数据操作,例如过滤转换、分组汇总、排序显示等;但是它们本质上都是针对表的操作,结果也是表。
不仅仅是查询语句,SQL 中的插入、更新和删除都以集合为操作对象。我们再看一个插入数据的示例:
CREATE TABLE t(id INTEGER);
-- 适用于 MySQL、SQL Server 以及 PostgreSQL
INSERT INTO t(id)
VALUES (1), (2), (3);
我们首先使用 CREATE TABLE 语句创建了一个表,然后使用 INSERT INTO 语句插入数据。在执行插入操作之前,会在内存中创建一个包含 3 条数据的临时集合(表),然后将该集合插入目标表中。由于我们通常一次插入一条数据,以为是按照数据行进行插入;但实际上,一条数据也是一个集合,只不过它只有一个元素而已。
Oracle 不支持以上插入多行数据的语法,可以使用下面的插入语句:
-- 适用于 Oracle
INSERT INTO t(id)
SELECT 1 FROM DUAL
UNION ALL
SELECT 2 FROM DUAL
UNION ALL
SELECT 3 FROM DUAL;
UNION ALL 是 SQL 中的并集运算,用于将两个集合组成一个更大的集合。此外,SQL 还支持交集运算(INTERSECT)、差集运算(EXCEPT)以及笛卡儿积(Cartesian product)。我们后面会慢慢介绍。
安装数据库
我们这里介绍的 SQL 支持 MySQL、PostgreSQL、SQL Server 以及 Oracle 四种数据库,但是我们在演示的时候只用 MySQL 和 PostgreSQL 进行演示,因为这两个是开源的。
下面我们来介绍一下如何在 Linux 上安装 MySQL 和 PostgreSQL,这里我使用的是阿里云上的 CentOS 7.3,至于在 Windows 上如何安装这两个数据,这里就不介绍了,可以自己搜索一下,说实话 Windows 安装没有任何难度。安装完毕之后我们会在本地使用 DataGrip 这个数据库连接工具进行连接、并执行相关操作,当然你也可以使用 Navicat、甚至命令行操作也是可以的。
安装 MySQL
1. 我们需要去 https://dev.mysql.com/downloads/mysql/ 下载 MySQL 所需要的安装包。
默认显示的是最新版,当然你也可以点击 Archives 来指定下载的版本,这里我选择的版本是 8.0.18。
然后是选择 Operating System,页面默认显示的便是你当前的操作系统,但这里我们下载安装在 CentOS 7 上的 MySQL,所以将操作系统选择为:Red Hat Enterprise Linux / Oracle Linux。
注意当你选择操作系统之后,下面会多出来一个下拉菜单:选择 OS Version,也就是指定 Linux 内核版本,这里我们使用的是 CentOS 7,所以选择 Red Hat Enterprise Linux 7 / Oracle Linux 7 (x86, 64-bit)。
然后我们就可以安装了,下面会提供很多种安装包,我们找到 RPM Bundle(一般是第一个),然后点击 Download 下载即可。
2. 下载完毕之后是一个 tar 包,我们将其丢到阿里云服务器上。
上传成功之后先不着急安装,我们先查看当前是否安装了 MySQL 或者 MariaDB,如果安装了那么将其卸载掉(如果你执行安装 MySQL 8.x 版本的话),具体方式如下:
[root@matsuri ~]# rpm -qa | grep mariadb
mariadb-libs-5.5.68-1.el7.x86_64
# 卸载掉 MariaDB
[root@matsuri ~]# rpm -e mariadb-libs-5.5.68-1.el7.x86_64 --nodeps
# 再次查看
[root@matsuri ~]# rpm -qa | grep mariadb
然后 cd 到 /usr/local 目录,这个目录是存放一些本地的共享资源的,然后我们在里面创建一个名叫 mysql 的目录,直接 mkdir mysql 即可。
接下来将之前上传的 tar 包移动到 mysql 下,解压即可,或者你直接解压到 mysql 目录中也可以。
[root@matsuri ~]# ll
total 668804
-rw-r--r-- 1 root root 684851200 Dec 26 16:32 mysql-8.0.18-1.el7.x86_64.rpm-bundle.tar
[root@matsuri ~]# mkdir /usr/local/mysql
[root@matsuri ~]# tar -xvf mysql-8.0.18-1.el7.x86_64.rpm-bundle.tar -C /usr/local/mysql/
mysql-community-libs-8.0.18-1.el7.x86_64.rpm
mysql-community-devel-8.0.18-1.el7.x86_64.rpm
mysql-community-embedded-compat-8.0.18-1.el7.x86_64.rpm
mysql-community-libs-compat-8.0.18-1.el7.x86_64.rpm
mysql-community-common-8.0.18-1.el7.x86_64.rpm
mysql-community-test-8.0.18-1.el7.x86_64.rpm
mysql-community-server-8.0.18-1.el7.x86_64.rpm
mysql-community-client-8.0.18-1.el7.x86_64.rpm
[root@matsuri ~]# cd /usr/local/mysql/
[root@matsuri mysql]# ll
total 668812
-rw-r--r-- 1 7155 31415 40104640 Sep 23 2019 mysql-community-client-8.0.18-1.el7.x86_64.rpm
-rw-r--r-- 1 7155 31415 611436 Sep 23 2019 mysql-community-common-8.0.18-1.el7.x86_64.rpm
-rw-r--r-- 1 7155 31415 6915400 Sep 23 2019 mysql-community-devel-8.0.18-1.el7.x86_64.rpm
-rw-r--r-- 1 7155 31415 23683600 Sep 23 2019 mysql-community-embedded-compat-8.0.18-1.el7.x86_64.rpm
-rw-r--r-- 1 7155 31415 3877664 Sep 23 2019 mysql-community-libs-8.0.18-1.el7.x86_64.rpm
-rw-r--r-- 1 7155 31415 1363968 Sep 23 2019 mysql-community-libs-compat-8.0.18-1.el7.x86_64.rpm
-rw-r--r-- 1 7155 31415 450282440 Sep 23 2019 mysql-community-server-8.0.18-1.el7.x86_64.rpm
-rw-r--r-- 1 7155 31415 158001648 Sep 23 2019 mysql-community-test-8.0.18-1.el7.x86_64.rpm
[root@matsuri mysql]#
3. 使用 rpm 进行安装。
[root@matsuri mysql]# rpm -ivh mysql-community-common-8.0.18-1.el7.x86_64.rpm --nodeps --force
warning: mysql-community-common-8.0.18-1.el7.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 5072e1f5: NOKEY
Preparing... ################################# [100%]
Updating / installing...
1:mysql-community-common-8.0.18-1.e################################# [100%]
[root@matsuri mysql]# rpm -ivh mysql-community-libs-8.0.18-1.el7.x86_64.rpm --nodeps --force
warning: mysql-community-libs-8.0.18-1.el7.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 5072e1f5: NOKEY
Preparing... ################################# [100%]
Updating / installing...
1:mysql-community-libs-8.0.18-1.el7################################# [100%]
[root@matsuri mysql]# rpm -ivh mysql-community-client-8.0.18-1.el7.x86_64.rpm --nodeps --force
warning: mysql-community-client-8.0.18-1.el7.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 5072e1f5: NOKEY
Preparing... ################################# [100%]
Updating / installing...
1:mysql-community-client-8.0.18-1.e################################# [100%]
[root@matsuri mysql]# rpm -ivh mysql-community-server-8.0.18-1.el7.x86_64.rpm --nodeps --force
warning: mysql-community-server-8.0.18-1.el7.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 5072e1f5: NOKEY
Preparing... ################################# [100%]
Updating / installing...
1:mysql-community-server-8.0.18-1.e################################# [100%]
[root@matsuri mysql]#
通过 rpm -qa | grep mysql 命令查看 mysql 的安装包。
[root@matsuri mysql]# rpm -qa | grep mysql
mysql-community-libs-8.0.18-1.el7.x86_64
mysql-community-client-8.0.18-1.el7.x86_64
mysql-community-server-8.0.18-1.el7.x86_64
mysql-community-common-8.0.18-1.el7.x86_64
[root@matsuri mysql]#
4. MySQL 数据库的初始化和相关配置。
[root@matsuri mysql]# mysqld --initialize
# 安装之后会自动创建一个 mysql组、该组下面有一个 mysql 用户, 我们赋予其操作 /var/lib/mysql 目录的权限
[root@matsuri mysql]# chown mysql:mysql /var/lib/mysql -R
# 开启服务
[root@matsuri mysql]# systemctl start mysqld.service
# 设置开启自启
[root@matsuri mysql]# systemctl enable mysqld
[root@matsuri mysql]#
5. 查看数据库的初始密码并进行修改。
[root@matsuri mysql]# cat /var/log/mysqld.log | grep password
...... A temporary password is generated for root@localhost: fwHt=wN<g4aa
[root@matsuri mysql]#
fwHt=wN<g4aa 便是使用 root 登陆的密码,这个密码是随机生成的,然后我们把它改掉。使用初始密码登入到数据库中,然后使用如下命令对密码进行修改:
ALTER USER 'root'@'localhost' IDENTIFIED WITH MYSQL_NATIVE_PASSWORD BY '你的密码';
然后退出,使用新密码进行登录,发现登录成功。
6. 通过以下命令,进行远程访问的授权。
# 创建一个用户叫 root, 这个是从外界连接的时候所使用的用户
# 然后 % 表示接收任意的 IP, 也就是任何一台计算机都可以通过 root 用户来连接
# 同理密码也是从外界连接的时候所使用的密码
create user 'root'@'%' identified with mysql_native_password by '你的密码';
# 当然你也可以创建其它用户, 比如: create user 'mea'@'%' identified with mysql_native_password by '123456';
# 那么外界便可以通过 用户名: "mea", 密码: "123456" 连接到当前服务器上的 MySQL
# 进行授权
grant all privileges on *.* to 'root'@'%' with grant option;
# 刷新权限
flush privileges;
7. 使用 DataGrip 连接工具进行连接测试。
显示连接成功,并成功获取 mysql 库下面的表名。
至于 MySQL 的一些配置可以通过配置文件 /etc/my.cnf 进行修改。
安装 PostgreSQL
安装 PostgreSQL 比较简单,我们直接去 https://www.postgresql.org/ 页面,点击 Download,然后会进入如下页面:
直接点击 Linux,会弹出 Linux 发行版种类,让你选择,我们选择 Red Hat/CentOS。
之后会进入新的页面,让你选择版本,操作系统种类以及架构。
根据当前的系统进行选择,完毕之后直接显示安装命令,我们按照上面的提示进行操作即可。安装完成之后,默认会有一个 postgres 用户,密码为空。
我们切换到 postgres 用户,然后输入 psql 即可进入控制台,输入 \password postgres
即可设置用户 postgres 的密码。
postgres=# \password postgres
Enter new password:
Enter it again:
postgres=#
下面我们就可以在外界通过 postgres 用户进行连接了,密码就是新设置的密码。但是如果现在就连接的话其实是连接不上的,因为此时 PostgreSQL 数据库还不接受外界的任何请求,我们需要修改配置文件,首先在目录 /var/lib/pgsql/11/data/ 中有两个重要的文件:pg_hba.conf、postgresql.conf。
pg_hba.conf: 配置对数据库的访问权限
postgresql.conf: 配置PostgreSQL数据库服务器的相应的参数
我们需要对这两个文件进行修改:
# 修改 pg_hba.conf, 在文件下方加入如下内容, 表示允许所有主机使用所有合法的用户名访问数据库,并提供加密的密码验证
host all all 0.0.0.0/0 trust
# 修改 postgresql.conf, 里面会有一个 #listen_addresses = "localhost", 这被注释掉了
# 凡是被注释掉的, 都是默认值, 我们将注释打开, 然后把 localhost 改成 *, 表示允许数据库监听来自任何主机的连接请求
listen_addresses = '*'
# 在这个文件里面我们可以修改很多配置, 比如监听的端口等等呢个
修改之后重启数据库服务,直接 systemctl restart postgresql-11 即可,下面连接就没有任何问题了,我们使用 DataGrip 连接工具测试一下。
所以我们看到安装非常的简单,没有任何的麻烦之处。但是很明显,这需要你的服务器是联网的,如果不能联网那么这个办法就失效了。所以下面我们介绍另一种安装 PostgreSQL 的方式,也就是编译安装。
编译安装 PostgreSQL
首先进入到 https://www.postgresql.org/ftp/source/ 中,会看到各种不同版本的PostgreSQL,这里我们随便选一个吧,就选10.12,首先10表示大版本,后面12属于小版本。这里我们只是介绍,并不会真的安装,我们后续使用的仍是上面通过 yum 安装的 PostgreSQL。
点击进去,再点击后缀为 tar.gz 的,即可开始源码包的下载,下载之后将其扔到服务器上。
然后 mkdir -p /opt/postgres
创建相应目录,然后执行tar -zxvf postgresql-10.12.tar.gz -C /opt/postgres
解压到该目录中。
进入到 /opt/postgres/postgresql-10.12
之后
chmod 755 configure
# 安装在/opt/postgres/下面
./configure -prefix=/opt/postgres/ --without-readline
# 编译安装
make && make install
编译安装之后,再 cd 到 contrib 目录中,执行 make && make install
,这里安装 contrib 目录下的一些第三方组织的一些工具代码。
因为 PostgreSQL 会默认将数据写在data目录下,所以执行:
mkdir -p /opt/postgres/data
但是 PostgreSQL 不允许使用root用户初始化数据库,所以需要创建一个新用户,这里叫 postgres
# 创建组和用户
groupadd postgres
useradd -g postgres postgres
可以的话,也可以设置用户 postgres 的密码,通过 passwd postgres 即可设置。然后将 /opt/postgres/
的权限交给postgres用户:
chown postgres:postgres /opt/postgres -R
chown postgres:postgres /opt/postgres/data -R
通过命令 su postgres
切换至 postgres 用户,在其 ~/.bashrc
中加入如下内容,并进行 source。
export PGHOME=/opt/postgres/
export PGDATA=/opt/postgres/data
export PATH=$PGHOME/bin:$PATH
export PATH=$PATH:/opt/postgres/bin
export MANPATH=$PGHOME/share/man:$MANPATH
export LANG=en_US.utf8
export DATE=`date +"%Y-%m-%d %H:%M:%S"`
export LD_LIBRARY_PATH=$PGHOME/lib:$LD_LIBRARY_PATH
alias rm='rm -i'
alias ll='ls -lh'
#alias pg_start='pg_ctl start -D $PGDATA'
#alias pg_stop='pg_ctl stop -D $PGDATA -m fast'
初始化数据库:
initdb -D /opt/postgres/data
然后启动服务:
pg_ctl -D /opt/postgres/data -l logfile start
一些配置我们可以通过 /opt/postgres/data/postgresql.conf
、/opt/postgres/data/pg_hba.conf
来进行设置。
最后我们可以通过如下命令来控制服务的启停。
# 启动
pg_ctl -D /opt/postgres/data -l /opt/postgres/logfile start
# 重启
pg_ctl -D /opt/postgres/data -l /opt/postgres/logfile restart
# 停止
pg_ctl -D /opt/postgres/data -l /opt/postgres/logfile stop
# 查看端口是否启用
netstat -anp | grep 5432
以上就是 MySQL 和 PostgreSQL 的安装方式,但是说实话我们搞开发的,应该很少会遇到安装、部署之类的工作,所以了解一下即可,我们的重点是使用 SQL 查询想要的数据。
小结
关系模型中定义了一个简单的数据结构,即关系(表),用于存储数据。SQL 是关系数据库的通用标准语言,它使用接近于自然语言(英语)的语法,通过声明的方式执行数据定义、数据操作、访问控制等。对于 SQL 而言,一切都是关系(表)。
现在主流的数据库有 MySQL、PostgreSQL、SQL Server、Oracle,当然还有其它的,比如:DB2、Teradata 等等。后续我们介绍的 SQL 都支持 MySQL、PostgreSQL、SQL Server、Oracle,不支持的会单独指出来,并使用 MySQL 和 PostgreSQL 进行演示。
如果觉得文章对您有所帮助,可以请囊中羞涩的作者喝杯柠檬水,万分感谢,愿每一个来到这里的人都生活愉快,幸福美满。
微信赞赏
支付宝赞赏