数据库的发展史
文件管理系统的缺点
数据库管理系统的优点
数据库管理系统及其基本功能和机构
关系型数据库
关系数据库
实体-联系模型E-R
联系类型
一对一联系(1:1)
如:学员a的基本信息对应其就业信息
一对多联系(1:n)
学员a的信息表对应考试成绩表,成绩表包括月考成绩,期中考试成绩,期末考试成绩,两个表之间通过学员id号关联,学员的一个id号对应多个考试成绩
学员成绩表被学员信息表中的id号所约束,因此学员成绩表依赖于学员信息表
外键 foreign key 简称FK
主键 简称PK
一对多用主外键来实现
主键表:被外键表依赖的表,即学员信息表
外键表:依赖于其他的表(主键表),即学员成绩表
外键字段:外键表依赖于主键表的字段,即id号
主键表中被外键表依赖的字段必须是主键
多对多联系(m:n)
课程与学员之间的关系就是多对多
学员表 student
课程表 class
使用第三张表student_class实现课程与学员之间的关系
student表
id name sex
1 a f
2 b m
3 c f
class 课程表
id classname
1 linux
2 python
3 java
student_class表
id student_id class_id
1 1 1
2 1 2
3 2 2
student_class表中的student_id、class_id属于外键,student表中的学员id号和class表中的课程id号属于相对应的主键
这样就实现了两张表的多对多的关系
对对多对的表操作进行查询,因为涉及到多个表,所以性能会差
简易数据规划流程
数据库的正规化分析
范式
1NF:
作者 书名1 书名2
a linux python
b python
有属性相同的列:书名
作者 书名1
a linux,python
b python
同一行有多个值
以上两种均不符合第一范式
解决方法:
a linux
a oython
b python
员工信息表
name city sex phone citynumber(城市区号)
a bj 010
b sh 021
复合主键:把多个字段(name,city)纳入主键,两个字段其中一个字段可以重复,但是两个一起不能重复
这时,区号citynumber只依赖于city,而不依赖于name,该属性没有完全依赖于主键,这就违反了第二范式
解决方法:
name city
a 1
b 2
b 2
cityid city citynumber
1 bj 010
2 sh 021
id name city sex phone citynumber(城市区号)
1 a bj 010
2 a sh 021
3 b sh 021
这里使用id号作为主键
这时,citynumber城市区号依赖于city,而city不属于主键;其他属性依赖于非主属性,违反了第三范式
解决方法:构建第三张表
id name city
1 a 1
2 b 2
3 b 2
cityid city citynumber
1 bj 010
2 sh 021
缺点:多表操作,数据库性能会变差
SQL概念
约束
基本概念
数据模型
MySQL历史
MySQL和MariaDB
MYSQL的特性
如果不想使用光盘自带的数据库,而是使用相对较新的数据库,可以使用官方提供的yum源进行安装
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.2/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
注意:在配置yum源时,要配置本地yum源,以解决依赖关系;安装新版本数据库名称为MariaDB-server
RPM包安装MySQL
[root@centos7-1 ~]#mysql_secure_installation
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.
Enter current password for root (enter for none): 写入当前mysql数据库root口令,默认没有口令,直接敲enter键
OK, successfully used password, moving on...
Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.
Set root password? [Y/n] y 是否设置root口令
New password: 写入新口令
Re-enter new password: 再次确认口令
Password updated successfully!
Reloading privilege tables..
... Success!
By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.
Remove anonymous users? [Y/n] y 是否移除匿名用户
... Success!
Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] y 是否禁止root远程登录
... Success!
By default, MariaDB comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n] y 是否移除test测试数据库
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] y 是否立即下载权限表
... Success!
Cleaning up...
All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.
Thanks for using MariaDB!
注意:如果设置有误,可以再次运行脚本进行设置
一旦改脚本运行过以后,想再次以匿名用户或者空口令登录,将不会被允许
MariaDB程序
用户账号
MySQL客户端
[root@centos7-1 ~]#cat test.sql
show databases;
[root@centos7-1 ~]#mysql -uroot -pcentos123456 < test.sql
Database
information_schema
mysql
performance_schema
注意:该命令显示结果中的列表与在mysql数据库中执行命令有细微差别,即不带边框
socket地址
如果客户端服务器在同一台主机,即使服务端口号没有打开也能连接
[root@centos7-1 ~]#iptables -A INPUT -p tcp --dport 3306 -j REJECT
[root@centos7-1 ~]#mysql -uroot -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 31
Server version: 5.5.56-MariaDB MariaDB Server
Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
注意:此时mysql -uroot -p 相当于mysql -uroot -p -hlocalhost,即在本机登录。
当客户端和服务器端在同一台主机,客户端登录服务器端并不是通过网络,也没有通过端口号,而是通过/usr/lib/mysql/mysql.socket文件进行连接,socket相当于文件传输中转站,只在本地生效,如果客户端跨网络访问服务端时,则socket文件不生效
如果删除该文件,则客户端无法在本机连接服务端
mysql.socket文件,在服务启动时创建,服务关闭时将不存在;
因此只需重启服务,该文件即可重新生成
执行命令
知识扩展:更改数据库终端提示符
查看mysqlman帮助: man mysql
搜索prompt,查看提示符修改表格
格式:
在linux中执行:
shell> mysql --prompt="(\u@\h) [\d]> " 这种更改只是临时的,下次登录如果不写就会恢复默认
想要永久保存,需要把更改写入配置文件中
vim /etc/profile.d/env.sh 把变量写入配置文件中
export MYSQL_PS1="(\u@\h) [\d]> " 声明变量
source /etc/profile.d/env.sh 使文件立即生效
或者写入数据库客户端配置文件语句块中
vim /etc/my.cnf.d/mysql-clients.cnf
[mysql]
prompt="\\r:\\m:\\s> "
注意:这两个文件生效的优先级:/etc/my.cnf.d/mysql-clients.cnf文件优先级大于/etc/profile.d/env.sh文件,即数据库客户端配置文件优先生效
另外,在工作中要把生产环境与测试环境的提示符区分开,防止混淆
服务器端配置
配置文件
/etc/my.cnf Global选项
/etc/mysql/my.cnf Global选项
SYSCONFDIR/my.cnf Global选项
$MYSQL_HOME/my.cnf Server-specific 选项
--defaults-extra-file=path
~/.my.cnf User-specific 选项
一般情况下,写入/etc/my.cnf配置文件中
MariaDB配置
通过二进制格式安装过程
pvcreate /dev/sda6
vgcreate vg_data /dev/sda6
lvcreate -n lv_mysql -l 100%FREE vg_data
mkfs.xfs /dev/vg_data/lv_mysql
vim /etc/fstab
UUID=ba3abbaf-b064-40b8-9127-f4f9453133f2 /mysql xfs defaults 0 0 把逻辑卷挂在到/mysql目录下,该目录用于存放数据库数据
mount -a
(2) 创建mysql用户和mysql组
mkdir /mysql/data 手动创建用户家目录
chown mysql.mysql /mysql/data 更改家目录所有者和所属组
useradd -r -s /sbin/nologin -d /mysql/data mysql
注意:在创建用户时,不能指定用户家目录(即-m选项,创建用户家目录),否则数据库安装完毕后,会自动创建以家目录中文件名为命名的数据库
(3) 准备二进制程序
tar xvf mariadb-10.2.18-linux-x86_64.tar.gz -C /usr/local/
注意:这里解压缩的文件路径必须指定为/usr/local目录,因为该文件在编译时就以该目录作为数据库应用程序存放位置。
另外,由于解压后的文件带有版本号,而该文件默认不能有版本号信息,因此,创建软链接指向该文件,而且这样的做法利用灰度发布的思路,有利于版本的切换(只需更改软链接即可)
cd /usr/local/
ln -s mariadb-10.2.18-linux-x86_64/ mysql/
此时,/usr/local/mariadb-10.2.18-linux-x86_64目录下文件所有者和所属组有问题,因此需要更改该目录下所有文件的所有者和所属组
chown -R root:mysql /usr/local/mysql/
(4) 准备配置文件
配置文件可根据系统提供的模板进行修改
配置文件模板所在路径:/usr/local/mysql/support-files/
该目录下有四个模板文件,每个数据库配置文件支持的内存大小不同
my-small.cnf 支持小于等于64M内存
my-medium.cnf 支持32M-64M内存
my-large.cnf 支持512M内存
my-huge.cnf 支持1G-2G内存
根据需求,选择不同的模板文件,在这里我们使用my-huge.cnf模板文件
另外,为了防止与系统自带的数据库配置文件冲突,把配置文件存放到/etc/mysql目录下并命名为my.cnf,因为该目录下配置文件优先级高于系统自带配置文件/etc/my.cnf,该目录需要手动创建
mkdir /etc/mysql/
cd /usr/local/mysql/support-files
cp my-huge.cnf /etc/mysql/my.cnf
更改配置文件:
vim /etc/mysql/my.cnf
[mysqld]
datadir=/mysql/data 指定数据存放路径
innodb_file_per_table=on
skip_name_resolve=on
innodb_file_per_table= on 数据库的每一个表都生成一个独立的文件,便于管理;默认情况下,所有的表存放在一个文件中,这样不利于管理。该文件在10.2以上版本的数据库默认开启此功能,可以不用添加
skip_name_resolve= on 禁止把ip反向解析为名字,因为反向解析会降低数据库的性能,因此建议关闭反向解析
(5)创建数据库文件
cd/usr/local/mysql/
./scripts/mysql_install_db--datadir=/app/data --user=mysql
(6)准备服务脚本,并启动服务
服务脚本可以参考系统中提供的模板文件:/usr/local/mysql/support-files/mysql.server
cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
把服务脚本复制到系统服务目录下重命名为mysqld,系统启动即可启动该服务
chkconfig --add mysqld 把服务加入服务列表中
service mysqld start 启动服务,由于该服务是二进制编译安装,因此启动服务使用service命令
为了便于使用,把该命令所在路径加入PATH变量
echo PATH=/usr/local/mysqld/bin:$PATH > /etc/profile.d/mysqld.sh
(7)安全初始化
/user/local/mysql/bin/mysql_secure_installation
至此,二进制安装mysql完成
源码编译安装mariadb
yum -y install bison bison-develzlib-devel libcurl-devel libarchive-devel boost-develgccgcc-c++ cmakencurses-devel gnutls-devel libxml2-devel openssl-devel libevent-devel libaio-devel
mkdir/data
useradd -r -s /sbin/nologin -d /data/mysql mysql
tar xvfmariadb-10.2.15.tar.gz
cd mariadb-10.2.15/
cmake . -DCMAKE_INSTALL_PREFIX=/app/mysql -DMYSQL_DATADIR=/data/mysql/ -DSYSCONFDIR=/etc -DMYSQL_USER=mysql -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_ARCHIVE_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITH_PARTITION_STORAGE_ENGINE=1 -DWITHOUT_MROONGA_STORAGE_ENGINE=1 -DWITH_DEBUG=0 -DWITH_READLINE=1 -DWITH_SSL=system -DWITH_ZLIB=system -DWITH_LIBWRAP=0 -DENABLED_LOCAL_INFILE=1 -DMYSQL_UNIX_ADDR=/data/mysql/mysql.sock -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci
提示:如果出错,执行rm-f CMakeCache.txt
cd/app/mysql/
scripts/mysql_install_db--datadir=/data/mysqldb/ --user=mysql
cp /app/mysql/support-files/my-huge.cnf/etc/my.cnf
cp /app/mysql/support-files/mysql.server/etc/init.d/mysqld
echo 'PATH=/app/mysql/bin:$PATH' > /etc/profile.d/mysql.sh
. /etc/profile.d/mysql.sh
chkconfig--add mysqld;service mysqldstart
实验:实现数据库多实例
实现数据库多实例
主要在测试环境中使用,多实例可以使相同版本,也可是使用不同版本
实现多实例需要提前准备:
1、用户
2、数据库存放数据的目录
3、数据库配置文件
4、数据库的启动脚本
5、数据库中存放系统数据的数据库文件
如果基于同一版本mysql数据库实现多实例:
1、二进制安装程序可使用同一个
2、应用程序可以使用同一个
3、用户账号可以是同一个
4、存放数据库的目录是各自独立的
5、配置文件是独立的,每个数据库的端口可能也不一样
6、服务的启动脚本是独立的,里面监听的端口号也不一样
yum安装mariadb实现多实例
mysql账号自动生成
[root@centos7 ~]# getent passwd mysql
mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin
二进制程序默认目录:/usr/libexec/mysqld
规划:
自定义端口号:3306 3307 3308
存放数据库的目录:
/data/mysql/{3306,3307,3308}
以3306为例:
/data/mysql/3306/{etc,log,data,pid,bin}
etc 存放配置文件
log 存放日志文件
data 存放数据库的数据
pid 存放数据库的进程
bin 存放数据库的二进制程序
(1)创建所需的各个目录
mkdir -pv /data/mysql/{3306,3307,3308}/{etc,data,socket,log,bin,pid}
[root@centos7 data]# tree mysql
mysql
├── 3306
│ ├── bin
│ ├── data
│ ├── etc
│ ├── log
│ ├── pid
│ └── socket
├── 3307
│ ├── bin
│ ├── data
│ ├── etc
│ ├── log
│ ├── pid
│ └── socket
└── 3308
├── bin
├── data
├── etc
├── log
├── pid
└── socket
更改mysql目录的所有者和所属组为mysql
chown -R mysql.mysql mysql
(2)准备数据库数据文件:
生成系统数据库文件,使用系统提供的脚本文件:/usr/bin/mysql_install_db
/usr/bin/mysql_install_db --datadir=/data/mysql/3306/data --user=mysql 生成3306端口号的数据库文件,指定存放数据的路径以及用户账号
/usr/bin/mysql_install_db --datadir=/data/mysql/3307/data --user=mysql 生成3307端口号的数据库文件,指定存放数据的路径以及用户账号
/usr/bin/mysql_install_db --datadir=/data/mysql/3308/data --user=mysql 生成3308端口号的数据库文件,指定存放数据的路径以及用户账号
(3)准备配置文件
参考系统生成的数据库配置文件,配置所需的数据库文件
3306端口号数据库配置文件
cp /etc/my.cnf /data/mysql/3306/etc/
vim /data/mysql/3306/etc/my.cnf
[mysqld]
port=3306 指定端口号
datadir=/data/mysql/3306/data 指定存放数据的文件路径
socket=/data/mysql/3306/socket/mysql.sock 指定存放socket文件路径
[mysqld_safe]
log-error=/data/mysql/3306/log/mariadb.log 指定存放日志文件路径
pid-file=/data/mysql/3306/pid/mariadb.pid 指定存放pid文件路径
# !includedir /etc/my.cnf.d 自定义数据量不存在子配置文件,注释掉该行
3307端口号数据库配置文件
cp /etc/my.cnf /data/mysql/3307/etc/
vim /data/mysql/3307/etc/my.cnf
[mysqld]
port=3307 指定端口号
datadir=/data/mysql/3307/data 指定存放数据的文件路径
socket=/data/mysql/3307/socket/mysql.sock 指定存放socket文件路径
[mysqld_safe]
log-error=/data/mysql/3307/log/mariadb.log 指定存放日志文件路径
pid-file=/data/mysql/3307/pid/mariadb.pid 指定存放pid文件路径
# !includedir /etc/my.cnf.d 自定义数据量不存在子配置文件,注释掉该行
3308端口号数据库配置文件
cp /etc/my.cnf /data/mysql/3308/etc/
vim /data/mysql/3308/etc/my.cnf
[mysqld]
port=3308 指定端口号
datadir=/data/mysql/3308/data 指定存放数据的文件路径
socket=/data/mysql/3308/socket/mysql.sock 指定存放socket文件路径
[mysqld_safe]
log-error=/data/mysql/3308/log/mariadb.log 指定存放日志文件路径
pid-file=/data/mysql/3308/pid/mariadb.pid 指定存放pid文件路径
# !includedir /etc/my.cnf.d 自定义数据量不存在子配置文件,注释掉该行
(4)准备mysql服务脚本
可以使用以下脚本实现服务脚本:
vim mysqld
#!/bin/bash
port=3306 自定义端口号,根据需求进行更改
mysql_user="root" 指定以roo身份启动mysql
mysql_pwd="" 指定mysql的root口令
cmd_path="/usr/bin" 指定mysql程序路径,该路径为yum安装默认路径,如果是二进制安装或者源码编译安装数据库,则根据需求进行更改
mysql_basedir="/data/mysql" mysql数据库的根目录,根据需求进行更改
mysql_sock="${mysql_basedir}/${port}/socket/mysql.sock" 调用定义变量,指定数据库socket文件路径
function_start_mysql() 定义函数,启动mysql
{
if [ ! -e "$mysql_sock" ];then
printf "Starting MySQL...\n"
${cmd_path}/mysqld_safe --defaults-file=${mysql_basedir}/${port}/etc/my.cnf &> /dev/null & 使用mysqld_safe命令调用配置文件启动mysql服务
else
printf "MySQL is running...\n"
exit
fi
}
function_stop_mysql() 定义函数,关闭mysql
{
if [ ! -e "$mysql_sock" ];then
printf "MySQL is stopped...\n"
exit
else
printf "Stoping MySQL...\n"
${cmd_path}/mysqladmin -u ${mysql_user} -p${mysql_pwd} -S ${mysql_sock} shutdown 使用mysqldadmin命令关闭mysql服务
fi
}
function_restart_mysql() 定义函数,重启mysql
{
printf "Restarting MySQL...\n"
function_stop_mysql
sleep 2
function_start_mysql
}
case $1 in 使用case语句进行条件判断调用哪个函数
start)
function_start_mysql
;;
stop)
function_stop_mysql
;;
restart)
function_restart_mysql
;;
*)
printf "Usage: ${mysql_basedir}/${port}/bin/mysqld {start|stop|restart}\n"
esac
把该脚本复制到各个数据库存放服务脚本的目录下,并把脚本中对应的端口号以及根目录路径进行更改
cp mysqld /data/mysql/3306/bin/
vim /data/mysql/3306/bin/mysqld
port=3306
mysql_basedir="/data/mysql"
cp /data/mysql/3306/bin/mysqld /data/mysql/3307/bin/mysqld
vim /data/mysql/3307/bin/mysqld
port=3307
cp /data/mysql/3306/bin/mysqld /data/mysql/3308/bin/mysqld
vim /data/mysql/3308/bin/mysqld
port=3308
服务开机自启动:
3306,3307,3308三个数据库都需要进行设置,这里以3306数据库为例:
cp /data/mysql/3306/bin/mysqld /etc/init.d/mysqld3306
vim /etc/init.d/mysqld3306
#!/bin/bash
#chkconfig: 345 20 80 添加服务启动和关闭级别
#description: mysql 3307 添加描述
chkconfig --add mysqld3306 把服务加入服务启动列表
注意:每个数据库的服务启动和关闭级别不能一样
或者把服务启动脚本存放到/etc/rc.local目录中
vim /etc/rc.local
/data/mysql/3306/bin/mysqld
/data/mysql/3307/bin/mysqld
/data/mysql/3308/bin/mysqld
对启动脚本增加执行权限
chmod +x /data/mysql/3306/bin/mysqld
chmod +x /data/mysql/3307/bin/mysqld
chmod +x /data/mysql/3308/bin/mysqld
至此,数据库各实例的用户、数据库文件、配置文件、服务启动脚本都已经准备完成
启动服务:
/data/mysql/3306/bin/mysqld start
/data/mysql/3307/bin/mysqld start
/data/mysql/3308/bin/mysqld start
连接数据库:
由于客户端和服务端在同一台主机上,因此可以通过本地socket文件连接数据库
mysql -S /data/mysql/3306/socket/mysql.sock 连接3306数据库
MariaDB [(none)]> show variables like "port"; 查看连接端口号
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| port | 3306 |
+---------------+-------+
1 row in set (0.01 sec)
[root@centos7 ~]# mysql -S /data/mysql/3306/socket/mysql.sock -e 'show variables like "port" ' 通过shell命令查看数据库端口号
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| port | 3306 |
+---------------+-------+
此时,数据库虽然创建完毕,但是数据库登录时却不需要口令,因此还需要对数据库设置登录口令
mysqladmin -uroot -S /data/mysql/3306/socket/mysql.sock password "centos123456"
通过端口号连接数据库
mysql -uroot -p -P 3306 -h127.0.0.1
[root@centos7 ~]# mysql -uroot -p -P 3306 -h127.0.0.1
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 1
Server version: 5.5.56-MariaDB MariaDB Server
Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
注意:在停止服务时,提示需要输入口令
[root@centos7 ~]# /data/mysql/3306/bin/mysqld stop
Stoping MySQL...
Enter password:
这是因为服务脚本中定义的提示服务函数中存在-p${mysql_pwd}选项
function_stop_mysql()
{
if [ ! -e "$mysql_sock" ];then
printf "MySQL is stopped...\n"
exit
else
printf "Stoping MySQL...\n"
${cmd_path}/mysqladmin -u ${mysql_user} -p${mysql_pwd} -S ${mysql_sock} shutdown
fi
}
但此时,启动服务脚本中设置的却是空口令
mysql_pwd=""
解决方法:
方法1:删除服务脚本定义函数中${cmd_path}/mysqladmin -u ${mysql_user} -p${mysql_pwd} -S ${mysql_sock} shutdown即可
方法2:先给3306端口号数据库添加口令,使用mysqlamdin命令添加口令
mysqladmin -uroot -S /data/mysql/3306/socket/mysql.sock password "centos123456"
然后再启动服务脚本中设置口令项添加设置的口令
mysql_pwd="centos123456"
同样的,3307和3308端口的数据库需要做同样的更改
3307端口号数据库:
设置口令
mysqladmin -uroot -S /data/mysql/3307/socket/mysql.sock password "centos123456"
更改服务脚本设置密码项
mysql_pwd="centos123456"
3308端口号数据库:
设置口令
mysqladmin -uroot -S /data/mysql/3308/socket/mysql.sock password "centos123456"
更改服务脚本设置密码项
mysql_pwd="centos123456"
注意:由于密码在服务脚本中以明文方式显示,因此脚本要做好保密措施。或者服务脚本中不写密码,在关闭服务时会出现输入密码提示,再输入密码即可
注意:mysqld_multi该命令也可以实现多实例,但要求必须是同一个数据库版本
关系型数据库的常见组件
SQL语言的兴起于语法标准
SQL语言规范
数据库对象
SQL语句分类
SQL语句构成
示例:
SELECT * SELECT子句
FROM products FROM子句
WHERE price>400 WHERE子句
说明:一组SQL语句,由三个子句构成,SELECT,FROM和WHERE是关键字
数据库操作
字符集:推荐选择utf8编码,支持全世界的语言;utf8mb64编码,兼容性更高,支持表情包
示例:
create database db1; 创建数据库
show create database db1; 查看创建数据库命令
注意,数据库默认使用的编码为latin1,即拉丁语
create database db2 character set=utf8mb4; 创建数据库db2,并指定数据库使用的编码格式
show collation 查看排序规则,排序规则推荐使用默认即可
表
创建表
直接创建表(可以分开多行书写):
MariaDB [db1]> create table students (
-> id int unsigned AUTO_INCREMENT primary key,
-> name varchar (50) NOT NULL,
-> sex enum('m','f'), 性别定义使用枚举(在男和女之间选其中一个)
-> age tinyint unsigned default 20
-> );
show create table students; 查看表的创建
desc students 查看表结构的定义
(2) 通过查询现存表创建;新表会被直接插入查询而来的数据
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name[(create_definition,…)] [table_options] [partition_options]select_statement
select * from 表名; 查看数据库中的某张表
create table newstudents seletc * from students; 查询students表,把表结构和信息导入newstudents表中
MariaDB [hellodb]> select * from newstudents; 此命令查看新表newstudents的内容
MariaDB [hellodb]> desc newstudents; 查看新表的表结构
+-----------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| StuID | int(10) unsigned | NO | | 0 | |
| Name | varchar(50) | NO | | NULL | |
| Age | tinyint(3) unsigned | NO | | NULL | |
| Gender | enum('F','M') | NO | | NULL | |
| ClassID | tinyint(3) unsigned | YES | | NULL | |
| TeacherID | int(10) unsigned | YES | | NULL | |
+-----------+---------------------+------+-----+---------+-------+
6 rows in set (0.01 sec)
MariaDB [hellodb]> desc students; 查看旧表的表结构
+-----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+----------------+
| StuID | int(10) unsigned | NO | PRI | NULL | auto_increment |
| Name | varchar(50) | NO | | NULL | |
| Age | tinyint(3) unsigned | NO | | NULL | |
| Gender | enum('F','M') | NO | | NULL | |
| ClassID | tinyint(3) unsigned | YES | | NULL | |
| TeacherID | int(10) unsigned | YES | | NULL | |
+-----------+---------------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)
跨数据库创建表
在db1数据库中创建newstudents表,从hellodb数据库复制students表的结构和内容
MariaDB [db1]> create table newstudents select * from hellodb.students;
Query OK, 25 rows affected (0.01 sec)
Records: 25 Duplicates: 0 Warnings: 0
查询表
MariaDB [db1]> show tables;
+---------------+
| Tables_in_db1 |
+---------------+
| newstudents |
| students |
+---------------+
2 rows in set (0.00 sec)
查询表内容
MariaDB [db1]> select * from newstudents;
(3) 通过复制现存的表的表结构创建,但不复制数据
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name{ LIKE old_tbl_name| (LIKE old_tbl_name) }
MariaDB [db1]> create table test like newstudents; 创建新表test,该表为空表
查看两张表的表结构,发现表结构一致
MariaDB [db1]> desc test;
+-----------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| StuID | int(10) unsigned | NO | | 0 | |
| Name | varchar(50) | NO | | NULL | |
| Age | tinyint(3) unsigned | NO | | NULL | |
| Gender | enum('F','M') | NO | | NULL | |
| ClassID | tinyint(3) unsigned | YES | | NULL | |
| TeacherID | int(10) unsigned | YES | | NULL | |
+-----------+---------------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
MariaDB [db1]> desc newstudents;
+-----------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| StuID | int(10) unsigned | NO | | 0 | |
| Name | varchar(50) | NO | | NULL | |
| Age | tinyint(3) unsigned | NO | | NULL | |
| Gender | enum('F','M') | NO | | NULL | |
| ClassID | tinyint(3) unsigned | YES | | NULL | |
| TeacherID | int(10) unsigned | YES | | NULL | |
+-----------+---------------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
查看test表的内容,发现新表test为空
MariaDB [db1]> select * from test;
Empty set (0.00 sec)
知识扩展:
使用以下语法也可以只复制表结构,不复制表内容
create table test2 newstudents select * from hellodb.students where 1=0;
在第二种语法的基础之上,添加一条不成立的判断语句where 1=0即可
另外,数据库在5.5版本中,数据库存在一个缺点:数据库文件所在目录中,数据被集中存放在一个表ibdata1中,并没有存放各自的目录下如(db1,db2,hellodb等),各自目录下只是存放了表的定义,管理起来非常不方便。而10以上版本mariadb数据库则没有这种缺点.
解决方法:
在配置文件/etc/my.cnf中添加innodb_file_per_table=on即可
在之前编译安装数据库准备配置文件时,我们提到过该项
vim /etc/my.cnf
innodb_file_per_table=on 是指存放表时,每张表分开存放
更改后重启数据库
systemctl restart mariadb
如果再添加新的数据库,每张表将会分开存放
表操作
数据类型
数据类型
tinyint(m) 1个字节范围(-128~127)
smallint(m) 2个字节范围(-32768~32767)
mediumint(m) 3个字节范围(-8388608~8388607)
int(m) 4个字节范围(-2147483648~2147483647)
bigint(m) 8个字节范围(+-9.22*10的18次方)
加了unsigned,则最大值翻倍,如:tinyintunsigned的取值范围为(0~255)
int(m)里的m是表示SELECT查询结果集中的显示宽度,并不影响实际的取值范围,规定了MySQL的一些交互工具(例如MySQL命令行客户端)用来显示字符的个数。对于存储和计算来说,Int(1)和Int(20)是相同的
BOOL,BOOLEAN:布尔型,是TINYINT(1)的同义词。zero值被视为假,非zero值视为真
char(n) 固定长度,最多255个字符
varchar(n) 可变长度,最多65535个字符
tinytext 可变长度,最多255个字符
text 可变长度,最多65535个字符
mediumtext 可变长度,最多2的24次方-1个字符
longtext 可变长度,最多2的32次方-1个字符
BINARY(M) 固定长度,可存二进制或字符,长度为0-M字节
VARBINARY(M) 可变长度,可存二进制或字符,允许长度为0-M字节
内建类型:ENUM枚举, SET集合
date 日期'2008-12-2'
time 时间'12:25:36'
datetime 日期时间'2008-12-2 22:06:44'
timestamp 自动存储记录修改时间
YEAR(2), YEAR(4):年份
timestamp字段里的时间数据会随其他字段修改的时候自动刷新,这个数据类型的字段可以存放这条记录最后被修改的时间
修饰符
NULL 数据列可包含NULL值
NOT NULL 数据列不允许包含NULL值
DEFAULT 默认值
PRIMARY KEY 主键
UNIQUE KEY 唯一键
CHARACTER SET name 指定一个字符集
AUTO_INCREMENT 自动递增,适用于整数类型
UNSIGNED 无符号
示例:
CREATE TABLE students (id int UNSIGNED NOT NULL PRIMARY KEY,name VARCHAR(20)NOT NULL,age tinyint UNSIGNED);
DESC students;
CREATE TABLE students2 (id int UNSIGNED NOT NULL ,name VARCHAR(20) NOT NULL,age tinyint UNSIGNED,PRIMARY KEY(id,name));
表操作
示例:修改表
ALTER TABLE students RENAME s1;
ALTER TABLE s1 ADD phone varchar(11) AFTER name;
ALTER TABLE s1 MODIFY phone int;
ALTER TABLE s1 CHANGE COLUMN phone mobile char(11);
ALTER TABLE s1 DROP COLUMN mobile;
Help ALTER TABLE 查看帮助
ALTER TABLE students ADD gender ENUM('m','f')
ALETR TABLE students CHANGE id sid int UNSIGNED NOT NULL PRIMARY KEY;
ALTER TABLE students ADD UNIQUE KEY(name);
ALTER TABLE students ADD INDEX(age);
DESC students;
SHOW INDEXES FROM students;
ALTER TABLE students DROP age;
DML语句
一次性添加一条记录
insert into students (name,phone,sex,age)values('mage','10086','m','30');
一次性添加多条记录
MariaDB [db1]> insert into students (name,phone,sex,age)values('wang','10000','m','20'),('li','111111','m','20');
(2)INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
SET col_name={expr | DEFAULT}, …
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] … ]
把其他数据库的表导入数据库中
insert ... select 写法
insert into students(name,phone,sex,age) select name,phone,sex,age from db1.students;
注意:数据类型必须一致
(3)INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name[(col_name,…)]
SELECT …
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] … ]
把其他数据库的表导入数据库中
insert ... set写法
insert into students set name='han',sex='m';
update students set sex='f' where id=5;
可同时更改多个字段:
update students set name='li',sex='f' where id=5;
把id为5的字段名字和性别进行更改
数据库修改时一定要添加限制条件,否则将修改所有行的指定字段
为了避免出现忘记添加限制条件,可以使用以下选项:
在登录数据库时,加上-U选项,即mysql -U -uroot -p
加上-U选项后,如果在数据库中执行命令忘记添加限制条件时,会出现错误信息
MariaDB [db2]> update students set name='li',sex='f';
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
为了使用方便,实现不输入-U选项也会有错误提示
在数据库客户端配置文件mysql语句块中添加safe-updates
vim /etc/my.cnf.d/mysql-clients.cnf
[mysql]
safe-updates
DQL语句
SELECT相关用法
select stuid as 学员编号,name 姓名,age 年龄 from students; 把关键字段以中文显示,而且字段显示的前后顺序可以自定义
+--------------+---------------+--------+
| 学员编号 | 姓名 | 年龄 |
+--------------+---------------+--------+
| 1 | Shi Zhongyu | 22 |
| 2 | Shi Potian | 22 |
| 3 | Xie Yanke | 53 |
| 4 | Ding Dian | 32 |
| 5 | Yu Yutong | 26 |
| 6 | Shi Qing | 46 |
+--------------+---------------+--------+
示例:
比较操作符
select * from students where classid=1; 挑选出students表中班级编号为1的学员
注意:这里表名大小写敏感,书写时要与表名一致;而字段名则大小写不敏感,不用与表中字段名一致,但为了使得命令规范化,尽量使其与原内容格式保持一致。
select * from students where age > 30 and age <50;
between and 命令:
select * from students where age between 30 and 50;
挑出students表中年龄大于30小于50岁的学员
这两种写法类似,但是要注意,between and命令表示闭区间,包括30和50;而大于和小于号则是开区间,并不包括30和50
in命令:
select * from students where classid in (1,2,3);
IS NULL和IS NOT NULL命令:
select * from students where teacherid is null;
select * from students where teacherid is not null;
distinct 去除重复列
select distinct classid from students ;
like:支持通配符
% 匹配任意长度的字符
select * from students where name like 's%'; 选择以s开头的学员
select * from students where name like '%o'; 选择以o结尾的学员
建议使用左前缀写法,即's%',因为在性能优化方面,右后缀写法'%o'和包含写法'%o%'会带来性能的影响
rlike和regexp:支持正则表达式
select * from students where name rlike '^s';
这种写法不推荐使用,因为这种写法性能更差
order by:排序
select * from students order by age; 以年龄排序,默认正序排序
select * from students order by age desc; 倒序排序
默认排序是根据排序规则进行排序的
show character set; 查看默认排序规则
简体中文 gb2312
LIMIT [[offset,]row_count]: 对显示结果进行行数数量限制
select * from students limit 3;
limit 2,3 2是指偏移量,3是指显示行数
select * from students order by age limit 2,3; 是指跳过前两个,显示后三个
group:分组,分类别
count() 函数 返回select命令中检索到的行中非null值的数目
注意()内的字段的值为非空字段,即该字段的值中不能出现null,否则将不能查询出准确的值
MariaDB [hellodb]> select count(*) from students ;
+----------+
| count(*) |
+----------+
| 25 |
+----------+
1 row in set (0.00 sec)
select classid,count(*) from students group by classid ;
统计每个班级中的人数,即以班级id为分组,统计每个班级中的总人数
一旦做分组,select 后跟的语句必须是两种内容:第一,要写分组本身,第二,要跟聚合函数,即做汇总的数据,如:最大值max,最小值min,平均值avg等
如:
select classid,min(age) from students group by classid ;
统计每个班级中最小年龄的人
先分组再做过滤
注意:一旦分组,如果要在分组后再做条件过滤,则不能使用where,而是要使用having
select classid,avg(age) from students group by classid having classid in (1,2);
统计students表中1班2班的平均年龄
select classid,avg(age) from students where gender = 'm' group by classid having classid in (1,2);
统计1班2班中男生的平均年龄
注意:如果先过滤后分组,则还是使用where
对多个字段分组:
select classid,gender,count(*) from students group by classid,gender;
统计每个班级中的男生女生分别有几个,即以班级作为分组后,再以性别作为分组进行统计
select * from students where birth between '1988-01-01 00:00:00' and '1998-12-31 00:00:00';
从student表中查询出生日期在1988年到1998年的人
课后练习:
导入hellodb.sql生成数据库
(1) 在students表中,查询年龄大于25岁,且为男性的同学的名字和年龄
select * from students where age > 25 and gender='M';
(2) 以ClassID为分组依据,显示每组的平均年龄
select avg(age) from students group by classid;
(3) 显示第2题中平均年龄大于30的分组及平均年龄
select classid,avg(age) from students group by classid having avg(age) > 30;
(4) 显示以L开头的名字的同学的信息
select * from students where name like 'L%';
或select * from students where name rlike '^L';
(5) 显示TeacherID非空的同学的相关信息
select * from students where teacherid is not null;
(6) 以年龄排序后,显示年龄最大的前10位同学的信息
select * from students order by age desc limit 10 ;
(7) 查询年龄大于等于20岁,小于等于25岁的同学的信息
select * from students where age between 20 and 25;
注意:大于小于号为开区间,不包括20或25.
多表查询
示例:
SELECT s.aage,s.ClassIDFROM (SELECT avg(Age) AS aage,ClassIDFROM students WHERE ClassIDIS NOT NULL GROUP BY ClassID) AS s WHERE s.aage>30;
SELECT Name,AgeFROM students UNION SELECT Name,AgeFROM teachers
课后练习:
导入hellodb.sql,以下操作在students表上执行
1、以ClassID分组,显示每班的同学的人数
select classid,class,numofstu from classes;
2、以Gender分组,显示其年龄之和
select avg(age) from students group by gender;
3、以ClassID分组,显示其平均年龄大于25的班级
select classid,avg(age) from students group by classid having avg(age) > 25;
4、以Gender分组,显示各组中年龄大于25的学员的年龄之和
select gender,sum(age) from students where age > 25 group by gender;
5、显示前5位同学的姓名、课程及成绩
select student_name,course,score from courses as c inner join (select st.name as student_name,courseid,score from scores as sc inner join (select * from students limit 5) as st on st.stuid=sc.stuid )as a on c.courseid=a.courseid;
6、显示其成绩高于80的同学的名称及课程;
select student_name,course,score from courses as c inner join (select st.name as student_name,courseid,score from scores as sc inner join (select * from students limit 5) as st on st.stuid=sc.stuid group by name)as a on c.courseid=a.courseid having score > 80;
7、求前8位同学每位同学自己两门课的平均成绩,并按降序排列
select st.name as student_name,avg(score) as sc_avg from students as st inner join scores as sc on st.stuid=sc.stuid group by st.stuid order by sc_avg desc;
8、显示每门课程课程名称及学习了这门课的同学的个数
select c.course,count(stuid) as studnet_count from scores as s left join courses as c on s.courseid=c.courseid group by s.courseid;
9、显示其年龄大于平均年龄的同学的名字
select name from students where age > (select avg(age) from students);
10、显示其学习的课程为第1、2,4或第7门课的同学的名字
select name from students as st inner join (select distinct sc.stuid from scores as sc inner join (select * from courses where courseid in(1,2,4) or courseid in (7)) as c on sc.courseid=c.courseid) as a on st.stuid=a.stuid;
11、显示其成员数最少为3个的班级的同学中年龄大于同班同学平均年龄的同学
select student.name,student.age,student.classid,second.avg_age from (select students.name as name ,students.age as age,students.classid as classid from students left join (select count(name) as num,classid as classid from students group by classid having num>=3) as first on first.classid=students.classid) as student,(select avg(age) as avg_age,classid as classid from students group by classid) as second where student.age>second.avg_age and student.classid=second.classid;
12、统计各班级中年龄大于全校同学平均年龄的同学
select name,classid,age from students where age > (select avg(age) from students);
视图