惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
小众软件
小众软件
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
L
LangChain Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
D
Docker
Cyberwarzone
Cyberwarzone
腾讯CDC
V
Vulnerabilities – Threatpost
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
AWS News Blog
AWS News Blog
GbyAI
GbyAI
Stack Overflow Blog
Stack Overflow Blog
MyScale Blog
MyScale Blog
C
CERT Recently Published Vulnerability Notes
T
Threat Research - Cisco Blogs
S
Securelist
C
Cybersecurity and Infrastructure Security Agency CISA
Security Archives - TechRepublic
Security Archives - TechRepublic
Know Your Adversary
Know Your Adversary
Security Latest
Security Latest
N
News and Events Feed by Topic
Attack and Defense Labs
Attack and Defense Labs
V
Visual Studio Blog
博客园 - 司徒正美
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
Intezer
P
Privacy International News Feed
爱范儿
爱范儿
T
The Exploit Database - CXSecurity.com
O
OpenAI News
云风的 BLOG
云风的 BLOG
博客园_首页
雷峰网
雷峰网
M
MIT News - Artificial intelligence
Project Zero
Project Zero
I
InfoQ
Hacker News: Ask HN
Hacker News: Ask HN
C
Cyber Attacks, Cyber Crime and Cyber Security
N
News and Events Feed by Topic
S
Security Affairs
S
Secure Thoughts
Y
Y Combinator Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
美团技术团队
The GitHub Blog
The GitHub Blog
B
Blog
H
Hacker News: Front Page

Nemo

再见,2025 Complete ORB-SLAM3 Setup Guide for Jetson Xavier NX with RealSense D455 20250723 再见,2024 Using CertBot for Automatic Secure EMQX Broker Create Your Own GPS Data Publisher Support SSL AGV Dispatching System Technical Documentation Finding Nemo No title 香港賽馬會呈獻系列:黑白——攝影敘事 再见,2023 团团是只猫 Design an FSM for Robot State Machines – Basics of Computer Science Data-driven robot lifespan: Collection 数据驱动的机器人寿命:收集、诊断、预测 Exploring the design space of binary search trees 特首来了 Large language models, explained with a minimum of math and jargon 设计有缓存异步逻辑的监控脚本并测试其资源占用 使用loguru记录串口数据并使用Docker搭建ARM开发环境 在vscode的Dev Container中构建.NET开发环境及使用doxygen和graphviz绘制函数调用图 State or Status? A*算法两种时间复杂度 /A* Algorithm: Two Types of Time Complexity 使用KD-Tree快速收敛到最近坐标点/Fast convergence to the nearest coordinate point using KD-Tree 翻译 || 总结 - Go语言中的空结构体(The empty struct) 再见,2022 从PE工作报告中能读出什么 Give me miles, give me truth AMR调度系统性能优化/AMR Dispatch System Performance Optimization 条件触发AMR避让流程/Conditionally triggered AMR avoidance process Docker实现调度系统整体部署/Docker implementation of dispatching system overall deployment 调度系统中加密算法的使用/增加SM4补0方法/Use of encryption algorithms in scheduling systems/add SM4 complementary 0 method 一篇关于北京四天三夜的攻略 2022 藏疆自驾 策划/招募书 AMR仿真模型/AMR Simulation Model 东东有鱼2022年会分享 使用perf-FlameGraph监控系统性能 Beyond Compare 4删除试用 你的灵魂有香气 Pyinstaller打包Python项目 [转载]Python中的单例模式的几种实现方式的及优化 - Nemo 再见! 2020 1024 UML软件建模 入职优必选一个月 写论文时 那些让你开心的软件 - Nemo 分享一个记录刷题次数的模版 LeetCode-查找表类算法题精析 PyCharm 调用vs 2010 C++库导致提示报错R6034解决方法 多种数据结构的Python实现形式 字节跳动-挑战字符串 选择排序 二分查找和大O表示法 算法中的动态规划问题 高高手课程-青山裕企人像摄影 笔记(内含福利)
MySQL基础教程
Nemo · 2019-08-07 · via Nemo

基础

Linux下安装MySQL

1.Linux下打开MySQL服务:

sudo service mysql start

2.Linux下安装MySQL:

#安装 MySQL 服务端、核心程序
sudo apt-get install mysql-server

#安装 MySQL 客户端
sudo apt-get install mysql-client    

3.验证MySQL是否安装成功

sudo netstat -tap | grep mysql

4.按需修改MySQL配置文件

sudo gedit /etc/mysql/my.cnf

Linux下启动MySQL

1.打开 MySQL 服务并使用 root 用户登录:

# 启动 MySQL 服务
sudo service mysql start          

# 使用 root 用户登录
mysql -u root

2.查看数据库

show databases;

3.连接数据库

选择连接其中一个数据库,语句格式为 use <数据库名>,这里可以不用加分号,这里我们选择 information_schema 数据库:

use information_schema

4.查看表

使用命令 show tables; 查看数据库中有哪些表:

show tables;

5.退出

使用命令 quit 或者 exit 退出 MySQL。

创建数据库并插入数据

准备

打开 MySQL 服务并使用 root 登录:

# 打开 MySQL 服务
sudo service mysql start

#使用 root 用户登录,密码为空
mysql -u root

新建数据库

语句格式为 CREATE DATABASE <数据库名字>;,(注意不要漏掉分号 ;),前面的 CREATE DATABASE 也可以使用小写,具体命令为:

CREATE DATABASE mysql_shiyan;

创建成功后输入命令 show databases; (注意不要漏掉;)检查一下:

show databases

在大多数系统中,SQL 语句都是不区分大小写的,因此以下语句都是合法的:

CREATE DATABASE name1;
create database name2;
CREATE database name3;
create DAtabaSE name4;

但是出于严谨,而且便于区分保留字(保留字(reserved word):指在高级语言中已经定义过的字,使用者不能再将这些字作为变量名或过程名使用。)和变量名,我们把保留字大写,把变量和数据小写。

数据库的删除:

DROP DATABASE mysql_shiyan;

连接数据库

由于一个系统中可能会有多个数据库,要确定当前是对哪一个数据库操作,使用语句 use <数据库名字>

use mysql_shiyan;

输入命令 show tables; 可以查看当前数据库里有几张表:

show tables;

数据表

数据表(table)简称表,它是数据库最重要的组成部分之一。数据库只是一个框架,表才是实质内容。

而一个数据库中一般会有多张表,这些各自独立的表通过建立关系被联接起来,才成为可以交叉查阅、一目了然的数据库。如下便是一张表:

ID name phone
01 Tom 110110110
02 Jack 119119119
03 Rose 114114114

在数据库中新建一张表的语句格式为:

CREATE TABLE 表的名字
(
列名a 数据类型(数据长度),
列名b 数据类型(数据长度),
列名c 数据类型(数据长度)
);

我们尝试在 mysql_shiyan 中新建一张表 employee,包含姓名,ID 和电话信息,所以语句为:

CREATE TABLE employee (id int(10),name char(20),phone int(12));

然后再创建一张表 department,包含名称和电话信息,想让命令看起来更整洁,你可以这样输入命令:

CREATE TABLE department
    -&gt; (
    -&gt; dpt_name CHAR(20),
    -&gt; dpt_phone INT(12)
    -&gt; );

这时候再 show tables; 一下,可以看到刚才添加的两张表:

2019-08-06-10-53-16.jpg

数据类型

在刚才新建表的过程中,我们提到了数据类型,MySQL 的数据类型和其他编程语言大同小异,下表是一些 MySQL 常用数据类型:

数据类型 大小(字节) 用途 格式
INT 4 整数
FLOAT 4 单精度浮点数
DOUBLE 8 双精度浮点数
ENUM 单选,比如性别 ENUM(‘a’,’b’,’c’)
SET 多选 SET(‘1′,’2′,’3’)
DATE 3 日期 YYYY-MM-DD
TIME 3 时间点或持续时间 HH:MM:SS
YEAR 1 年份值 YYYY
CHAR 0~255 定长字符串
VARCHAR 0~255 变长字符串
TEXT 0~65535 长文本数据

整数除了 INT 外,还有 TINYINT、SMALLINT、MEDIUMINT、BIGINT。

CHAR 和 VARCHAR 的区别: CHAR 的长度是固定的,而 VARCHAR 的长度是可以变化的,比如,存储字符串 “abc",对于 CHAR(10),表示存储的字符将占 10 个字节(包括 7 个空字符),而同样的 VARCHAR(12) 则只占用4个字节的长度,增加一个额外字节来存储字符串本身的长度,12 只是最大值,当你存储的字符小于 12 时,按实际长度存储。

ENUM和SET的区别: ENUM 类型的数据的值,必须是定义时枚举的值的其中之一,即单选,而 SET 类型的值则可以多选。

想要了解更多关于 MySQL 数据类型的信息,可以参考下面两篇博客。

插入数据

刚才我们新建了两张表,使用语句 SELECT * FROM employee;查看表中的内容,可以看到 employee 表中现在还是空的:

2019-08-06-10-59-10.jpg

我们通过 INSERT 语句向表中插入数据,语句格式为:

INSERT INTO 表的名字(列名a,列名b,列名c) VALUES(值1,值2,值3);

我们尝试向 employee 中加入 Tom、Jack 和 Rose:

INSERT INTO employee(id,name,phone) VALUES(01,&#039;Tom&#039;,110110110);

INSERT INTO employee VALUES(02,&#039;Jack&#039;,119119119);

INSERT INTO employee(id,name) VALUES(03,&#039;Rose&#039;);

有的数据需要用单引号括起来,比如 Tom、Jack、Rose 的名字,这是由于它们的数据类型是 CHAR 型。此外 VARCHAR,TEXT,DATE,TIME,ENUM 等类型的数据也需要单引号修饰,而 INT,FLOAT,DOUBLE 等则不需要。

第一条语句比第二条语句多了一部分:(id,name,phone) 这个括号里列出的,是将要添加的数据 (01,'Tom',110110110) 其中每个值在表中对应的列。而第三条语句只添加了 (id,name)两列的数据,所以在表中Rose的phone为NULL

现在我们再次使用语句 SELECT * FROM employee; 查看 employee 表,可见 Tom 和 Jack 的相关数据已经保存在其中了:

2019-08-06-11-08-51.jpg

习题

新建一个名为 library 的数据库,包含 book、reader 两张表,根据自己的理解安排表的内容并插入数据。保存截图。

create database library;
use library;

create table book(
  book_id int primary key,
  book_name varchar(50) not null
);

create table reader(
  reader_id int primary key,
  reader_name varchar(50) not null
);

SQL约束

介绍

约束是一种限制,它通过对表的行或列的数据做出限制,来确保表的数据的完整性、唯一性。本节实验将在实践操作中熟悉 MySQL 中的几种约束。

约束分类

约束是一种限制,它通过对表的行或列的数据做出限制,来确保表的数据的完整性、唯一性。

比如,规定一个用户的用户名不能为空值且没有重复的记录,这就是一种约束规则。

在MySQL中,通常有这几种约束:

约束类型: 主键 默认值 唯一 外键 非空
关键字: PRIMARY KEY DEFAULT UNIQUE FOREIGN KEY NOT NULL

建立含约束的表

为了方便介绍这几种约束,我们先建立一个数据库。

使用 git 命令将需要的数据文件下载到本地文件夹:

git clone https://github.com/shiyanlou/SQL3.git
CREATE DATABASE mysql_shiyan;

use mysql_shiyan;

CREATE TABLE department
(
  dpt_name   CHAR(20) NOT NULL,
  people_num INT(10) DEFAULT &#039;10&#039;,
  CONSTRAINT dpt_pk PRIMARY KEY (dpt_name)
);

CREATE TABLE employee
(
  id      INT(10) PRIMARY KEY,
  name    CHAR(20),
  age     INT(10),
  salary  INT(10) NOT NULL,
  phone   INT(12) NOT NULL,
  in_dpt  CHAR(20) NOT NULL,
  UNIQUE  (phone),
  CONSTRAINT emp_fk FOREIGN KEY (in_dpt) REFERENCES department(dpt_name)
);

CREATE TABLE project
(
  proj_num   INT(10) NOT NULL,
  proj_name  CHAR(20) NOT NULL,
  start_date DATE NOT NULL,
  end_date   DATE DEFAULT &#039;2015-04-01&#039;,
  of_dpt     CHAR(20) REFERENCES department(dpt_name),
  CONSTRAINT proj_pk PRIMARY KEY (proj_num,proj_name)
);

下载完成后,输入命令开启 MySQL 服务并使用 root 用户登录:

#打开 MySQL 服务
sudo service mysql start     

#使用 root 用户登录
mysql -u root  

刚才下载的 SQL3 目录下,有个文件 MySQL-03-01.sql,其中包含的代码可以新建一个数据库 mysql_shiyan,然后在其中创建三张表 departmentemployeeproject,它们包含了各种约束。

加载文件中的数据,需要在 MySQL 控制台中输入命令:

source /home/shiyanlou/Desktop/SQL3/MySQL-03-01.sql;

查看一下这个数据库,输入命令 show tables;,可见:

2019-08-06-15-32-25.jpg

主键

在数据库中,如果有两行记录数据完全一样,那么如何来区分呢? 答案是无法区分,如果有两行记录完全相同,那么对于 Mysql 就会认定它们是同一个实体,这于现实生活是存在差别的。

假如我们要存储一个学生的信息,信息包含姓名,身高,性别,年龄。

不幸的是有两个女孩都叫小梦,且她们的身高和年龄相同,数据库将无法区分这两个实体,这时就需要用到主键了。

主键 (PRIMARY KEY)是用于约束表中的一行,作为这一行的唯一标识符,在一张表中通过主键就能准确定位到一行,因此主键十分重要,主键不能有重复记录且不能为空

MySQL-03-01.sql 中,这里有主键:

2019-08-06-15-43-25.jpg

2019-08-06-15-44-06.jpg

dpt_pk为自定义主键名

还有一种特殊的主键——复合主键。主键不仅可以是表中的一列,也可以由表中的两列或多列来共同标识,比如:

2019-08-06-15-44-26.jpg

默认值约束

默认值约束 (DEFAULT) 规定,当有 DEFAULT 约束的列,插入数据为空时,将使用默认值。

默认值常用于一些可有可无的字段,比如用户的个性签名,如果用户没有设置,系统给他应该设定一个默认的文本,比如空文本或 ‘这个人太懒了,没有留下任何信息’

MySQL-03-01.sql 中,这段代码包含了 DEFAULT 约束:

2019-08-06-15-46-56.jpg

peoplr_num的默认值是10

DEFAULT 约束只会在使用 INSERT 语句(上一实验介绍过)时体现出来, INSERT 语句中,如果被 DEFAULT 约束的位置没有值,那么这个位置将会被 DEFAULT 的值填充,如语句:

# 正常插入数据
INSERT INTO department(dpt_name,people_num) VALUES(&#039;dpt1&#039;,11);

#插入新的数据,people_num 为空,使用默认值
INSERT INTO department(dpt_name) VALUES(&#039;dpt2&#039;);

输入命令 SELECT * FROM department;,可见表中第二行的people_num 被 DEFAULT 的值 (10) 填充:

2019-08-06-15-49-01.jpg

唯一约束

唯一约束 (UNIQUE) 比较简单,它规定一张表中指定的一列的值必须不能有重复值,即这一列每个值都是唯一的。

MySQL-03-01.sql 中,也有 UNIQUE 约束:

2019-08-06-15-50-49.jpg

当 INSERT 语句新插入的数据和已有数据重复的时候,如果有 UNIQUE 约束,则 INSERT 失败,比如:

INSERT INTO employee VALUES(01,&#039;Tom&#039;,25,3000,110110,&#039;dpt1&#039;);
INSERT INTO employee VALUES(02,&#039;Jack&#039;,30,3500,110110,&#039;dpt2&#039;);

2019-08-06-15-53-44.jpg

外键约束

外键 (FOREIGN KEY) 既能确保数据完整性,也能表现表之间的关系

比如,现在有用户表和文章表,给文章表中添加一个指向用户 id 的外键,表示这篇文章所属的用户 id,外键将确保这个外键指向的记录是存在的,如果你尝试删除一个用户,而这个用户还有文章存在于数据库中,那么操作将无法完成并报错。因为你删除了该用户过后,他发布的文章都没有所属用户了,而这样的情况是不被允许的。同理,你在创建一篇文章的时候也不能为它指定一个不存在的用户 id。

一个表可以有多个外键,每个外键必须 REFERENCES (参考) 另一个表的主键,被外键约束的列,取值必须在它参考的列中有对应值。

wm.png

在 INSERT 时,如果被外键约束的值没有在参考列中有对应,比如以下命令,参考列 (department 表的 dpt_name) 中没有 dpt3,则 INSERT 失败:

INSERT INTO employee VALUES(02,&#039;Jack&#039;,30,3500,114114,&#039;dpt3&#039;);

可见之后将 dpt3 改为 dpt2(department 表中有 dpt2),则插入成功:

wm _1_.png

非空约束

非空约束 (NOT NULL),听名字就能理解,被非空约束的列,在插入值时必须非空。

wm _2_.png

#INSERT 成功 age 为空,因为没有非空约束,表中显示 NULL
INSERT INTO employee(id,name,salary,phone,in_dpt) VALUES(03,&#039;Jim&#039;,3400,119119,&#039;dpt2&#039;);

#报错 salary 被非空约束,插入数据失败
INSERT INTO employee(id,name,age,phone,in_dpt) VALUES(04,&#039;Bob&#039;,23,123456,&#039;dpt1&#039;);

结果如图,插入数据失败:

wm _3_.png

此时 employee 表的内容为:

wm _4_.png

搭建一个简易的成绩管理系统的数据库

介绍

现需要构建一个简易的成绩管理系统的数据库,来记录几门课程的学生成绩。数据库中有三张表分别用于记录学生信息、课程信息和成绩信息。

数据表结构如下:

学生表(student):学生 id 、学生姓名和性别

wm _5_.png

课程表:课程 id 和课程名

wm.png

成绩表:成绩 id 、学生 id 、课程 id 和分数

wm _1_.png

目标

1.MySQL 服务处于运行状态

2.新建数据库的名称为 gradesystem

3.gradesystem 包含三个表:student、course、mark;

  • student 表包含3列:sid(主键)、sname、gender;
  • course 表包含2列:cid(主键)、cname;
  • mark 表包含4列:mid(主键)、sid、cid、score ,注意与其他两个表主键之间的关系。

4.将上述表中的数据分别插入到各个表中

提示

  • 建立表时注意 id 自增和键约束
  • 每个表插入语句可通过一条语句完成
$ sudo service mysql start

$ mysql -u root

mysql&gt; CREATE DATABASE gradesystem;

mysql&gt; use gradesystem

mysql&gt; CREATE TABLE student(
    -&gt; sid int NOT NULL AUTO_INCREMENT,
    -&gt; sname varchar(20) NOT NULL,
    -&gt; gender varchar(10) NOT NULL,
    -&gt; PRIMARY KEY(sid)
    -&gt; );

mysql&gt; CREATE TABLE course(
    -&gt; cid int NOT NULL AUTO_INCREMENT,
    -&gt; cname varchar(20) NOT NULL,
    -&gt; PRIMARY KEY(cid)
    -&gt; );

mysql&gt; CREATE TABLE mark(
    -&gt; mid int NOT NULL AUTO_INCREMENT,
    -&gt; sid int NOT NULL,
    -&gt; cid int NOT NULL,
    -&gt; score int NOT NULL,
    -&gt; PRIMARY KEY(mid),
    -&gt; FOREIGN KEY(sid) REFERENCES student(sid),
    -&gt; FOREIGN KEY(cid) REFERENCES course(cid)
    -&gt; );

mysql&gt; INSERT INTO student VALUES(1,&#039;Tom&#039;,&#039;male&#039;),(2,&#039;Jack&#039;,&#039;male&#039;),(3,&#039;Rose&#039;,&#039;female&#039;);

mysql&gt; INSERT INTO course VALUES(1,&#039;math&#039;),(2,&#039;physics&#039;),(3,&#039;chemistry&#039;);

mysql&gt; INSERT INTO mark VALUES(1,1,1,80),(2,2,1,85),(3,3,1,90),(4,1,2,60),(5,2,2,90),(6,3,2,75),(7,1,3,95),(8,2,3,75),(9,3,3,85);

SELECT语句详解

SQL 中最常用的 SELECT 语句,用来在表中选取数据。

  • SELECT 基本语法
  • 数学符号条件
  • AND OR IN
  • 通配符
  • 排序
  • SQL 内置函数和计算
  • 子查询与连接查询

在正式开始本实验内容之前,需要先下载相关数据库表,搭建好一个名为mysql_shiyan 的数据库(有三张表:department,employee,project),并向其中插入数据。

git clone https://github.com/shiyanlou/SQL4.git

下载完成后,输入命令开启 MySQL 服务并使用 root 用户登录:

#打开 MySQL 服务
sudo service mysql start     

#使用 root 用户登录
mysql -u root        

刚才下载的 SQL4 目录下,有两个文件 MySQL-04-01.sqlMySQL-04-02.sql,其中第一个文件用于创建数据库,第二个文件向数据库中插入数据。

加载文件中的数据,需要在 MySQL 控制台中输入命令,搭建数据库:

source /home/shiyanlou/Desktop/SQL4/MySQL-04-01.sql

向数据库插入数据:

source /home/shiyanlou/Desktop/SQL4/MySQL-04-02.sql

在数据库操作语句中,使用最频繁,也被认为最重要的是 SELECT 查询语句。之前的实验中,我们已经在不少地方用到了 SELECT * FROM table_name; 这条语句用于查看一张表中的所有内容。 而 SELECT 与各种限制条件关键词搭配使用,具有各种丰富的功能,这次实验就进行详细介绍。

基本的SELECT语句

SELECT 语句的基本格式为:

SELECT 要查询的列名 FROM 表名字 WHERE 限制条件;

如果要查询表的所有内容,则把 要查询的列名 用一个星号 *号表示,代表要查询表中所有的列。 而大多数情况,我们只需要查看某个表的指定的列,比如要查看 employee 表的 name 和 age:

SELECT name,age FROM employee;

2019-08-06-21-20-45.jpg

数学符号条件

SELECT 语句常常会有 WHERE 限制条件,用于达到更加精确的查询。WHERE限制条件可以有数学符号 (=,<,>,>=,<=) ,刚才我们查询了 name 和 age,现在稍作修改:

SELECT name,age FROM employee WHERE age&gt;25;

2019-08-06-21-25-40.jpg

或者查找一个名字为 Mary 的员工的 name,age 和 phone:

SELECT name,age,phone FROM employee WHERE name=&#039;Mary&#039;;

2019-08-06-21-26-57.jpg

“AND”与“OR”

从这两个单词就能够理解它们的作用。WHERE 后面可以有不止一条限制,而根据条件之间的逻辑关系,可以用 [条件一 OR 条件二]] 和 [条件一 AND 条件二] 连接:

例如,筛选出 age 小于 25,或 age 大于 30

SELECT name,age FROM employee WHERE age&lt;25 OR age&gt;30;

2019-08-06-21-28-39.jpg

#筛选出 age 大于 25,且 age 小于 30
SELECT name,age FROM employee WHERE age&gt;25 AND age&lt;30;

2019-08-06-21-30-01.jpg

而刚才的限制条件 age>25 AND age<30 ,如果需要包含25和30这两个数字的话,可以替换为 age BETWEEN 25 AND 30

SELECT name,age FROM employee WHERE age BETWEEN 25 AND 30;

2019-08-06-21-31-12.jpg

IN 和 NOT IN

关键词 INNOT IN 的作用和它们的名字一样明显,用于筛选“在”“不在”某个范围内的结果,比如说我们要查询在 dpt3dpt4 的人:

SELECT name,age,phone,in_dpt FROM employee WHERE in_dpt IN (&#039;dpt3&#039;,&#039;dpt4&#039;);

2019-08-06-22-35-20.jpg

NOT IN 的效果则是,如下面这条命令,查询出了不在 dpt1也不在 dpt3 的人:

SELECT name,age,phone,in_dpt FROM employee WHERE in_dpt NOT IN (&#039;dpt1&#039;,&#039;dpt3&#039;);

2019-08-06-22-39-35.jpg

通配符

关键字 LIKE 可用于实现模糊查询,常见于搜索功能中。

和 LIKE 联用的通常还有通配符,代表未知字符。SQL中的通配符是 _% 。其中 _ 代表一个未指定字符,% 代表不定个未指定字符

比如,要只记得电话号码前四位数为1101,而后两位忘记了,则可以用两个 _ 通配符代替:

SELECT name,age,phone FROM employee WHERE phone LIKE &#039;1101__&#039;;

这样就查找出了 1101开头的6位数电话号码

2019-08-06-22-44-31.jpg

另一种情况,比如只记名字的首字母,又不知道名字长度,则用 % 通配符代替不定个字符:

SELECT name,age,phone FROM employee WHERE name LIKE &#039;J%&#039;;

2019-08-06-22-47-24.jpg

对结果排序

为了使查询结果看起来更顺眼,我们可能需要对结果按某一列来排序,这就要用到 ORDER BY 排序关键词。默认情况下,ORDER BY 的结果是升序排列,而使用关键词 ASCDESC 可指定升序降序排序。 比如,我们按 salary 降序排列,SQL语句为:

SELECT name,age,salary,phone FROM employee ORDER BY salary DESC;

2019-08-06-22-50-24.jpg

如果后面不加 DESC 或 ASC 将默认按照升序排列。应用场景:博客系统中按时间先后顺序显示博文。

SQL 内置函数和计算

SQL 允许对表中的数据进行计算。对此,SQL 有 5 个内置函数,这些函数都对 SELECT 的结果做操作:

函数名: COUNT SUM AVG MAX MIN
作用: 计数 求和 求平均值 最大值 最小值

其中 COUNT 函数可用于任何数据类型(因为它只是计数),而 SUM 、AVG 函数都只能对数字类数据类型做计算,MAX 和 MIN 可用于数值、字符串或是日期时间数据类型。

具体举例,比如计算出 salary 的最大、最小值,用这样的一条语句:

SELECT MAX(salary) AS max_salary,MIN(salary) FROM employee;

有一个细节你或许注意到了,使用 AS 关键词可以给值重命名,比如最大值被命名为了 max_salary:

2019-08-06-22-56-13.jpg

子查询

上面讨论的 SELECT 语句都仅涉及一个表中的数据,然而有时必须处理多个表才能获得所需的信息。例如:想要知道名为 "Tom" 的员工所在部门做了几个工程。员工信息储存在 employee 表中,但工程信息储存在 project 表中。

对于这样的情况,我们可以用子查询:

SELECT of_dpt,COUNT(proj_name) AS count_project FROM project GROUP BY of_dpt
HAVING of_dpt IN
(SELECT in_dpt FROM employee WHERE name=&#039;Tom&#039;);

上面代码包含两个 SELECT 语句,第二个 SELECT 语句将返回一个集合的数据形式,然后被第一个 SELECT 语句用 in 进行判断。

HAVING 关键字可以的作用和 WHERE 是一样的,都是说明接下来要进行条件筛选操作。

区别在于 HAVING 用于对分组后的数据进行筛选

2019-08-06-23-01-23.jpg

子查询还可以扩展到 3 层、4 层或更多层。

连接查询

在处理多个表时,子查询只有在结果来自一个表时才有用。但如果需要显示两个表或多个表中的数据,这时就必须使用连接 (join) 操作。 连接的基本思想是把两个或多个表当作一个新的表来操作,如下:

SELECT id,name,people_num
FROM employee,department
WHERE employee.in_dpt = department.dpt_name
ORDER BY id;

这条语句查询出的是,各员工所在部门的人数,其中员工的 id 和 name 来自 employee 表,people_num 来自 department 表:

2019-08-06-23-12-59.jpg

另一个连接语句格式是使用 JOIN ON 语法,刚才的语句等同于:

SELECT id,name,people_num
FROM employee JOIN department
ON employee.in_dpt = department.dpt_name
ORDER BY id;

结果也与刚才的语句相同。

示例

使用连接查询的方式,查询出各员工所在部门的人数与工程数,工程数命名为 count_project。(连接 3 个表,并使用 COUNT 内置函数)

mysql&gt; SELECT name, people_num, COUNT(proj_name) AS count_project
    -&gt; FROM employee, department, project
    -&gt; WHERE in_dpt = dpt_name AND of_dpt = dpt_name
    -&gt; GROUP BY name, people_num;
+------+------------+---------------+
| name | people_num | count_project |
+------+------------+---------------+
| Jack |         12 |             2 |
| Mary |         12 |             2 |
| Jim  |         11 |             1 |
| Alex |         11 |             1 |
| Tom  |         15 |             2 |
| Rose |         10 |             1 |
+------+------------+---------------+
6 rows in set (0.00 sec)

前两行不必说了,从三张表选择三列数据;第三行设置三列数据的关系,dpt_name 是唯一值,of_dpt 和 in_dpt 的值必取自 dpt_name 这列,它们应该有外键关系,但不是必须的;第四行分组,分组不可或缺,否则会出现无意义的数据(一般来说连接查询语句中有 COUNT 就会有 GROUP BY),报一个 sql_mode 引起的错误,至于为什么选择 name 和 people_num 分组,大家可以试一下同时去掉 COUNT 和 GROUP BY 语句,看看其中的差异即可理解。

数据库及表的修改和删除

对数据库表和表中的内容做修改,删除,重命名

  • 数据库操作
  • 数据表操作
  • 更新和删除数据

在正式开始本实验内容之前,需要先下载相关代码。

该代码可以新建两个数据库,分别名为 test_01mysql_shiyan ,并在 mysql_shiyan 数据库中建 4 个表(department,employee,project,table_1),然后向其中插入数据。

git clone https://github.com/shiyanlou/SQL5.git

下载完成后,输入命令开启 MySQL 服务并使用 root 用户登录:

#打开 MySQL 服务
sudo service mysql start

#使用 root 用户登录
mysql -u root

加载文件中的数据,需要在 MySQL 控制台中输入命令,完成实验准备:

source /home/shiyanlou/Desktop/SQL5/MySQL-05.sql;

使用命令 SHOW DATABASES; 可以看到刚才运行MySQL-05.sql 文件生成的两个数据库:

2019-08-07-00-05-59.jpg

删除数据库

现在我们运行命令删除名为 test_01 的数据库:

DROP DATABASE test_01;

现在再次使用命令 SHOW DATABASES; 可以发现,test_01 数据库已经被成功删除

关于修改数据库

目前 Mysql 没有提供修改数据库名称的方法,因为这曾导致一系列安全问题。

在老版本中 RENAME DATABASE 可以修改数据库名称,这条命令在 MySQL 5.1.7 中被加入,但官方很快就发现这条命令所带来的危险,于是在 MySQL 5.1.23 中把这条命令移除。

事实上,数据库名几乎不会遇到必须修改的情况,如果你一定要这么做,比较安全的做法是重新建一个新库,然后将旧库中的数据转移到新库中,并且暂时不要删除旧的数据库,以防数据遗失。

对一张表的修改

重命名一张表

重命名一张表的语句有多种形式,以下 3 种格式效果是一样的:

RENAME TABLE 原名 TO 新名字;

ALTER TABLE 原名 RENAME 新名;

ALTER TABLE 原名 RENAME TO 新名;

进入数据库 mysql_shiyan :

use mysql_shiyan

使用命令尝试修改 table_1 的名字为 table_2

RENAME TABLE table_1 TO table_2;

wm.png

删除一张表

删除一张表的语句,类似于刚才用过的删除数据库的语句,格式是这样的:

DROP TABLE 表名字;

比如我们把 table_2 表删除:

DROP TABLE table_2;

wm _1_.png

对一列的修改(即对表结构的修改)

对表结构的修改,是本节实验的难点,有时候一些小的错误会造成不可挽回的后果,所以请细心操作。另外需要注意,非必要情况不要修改表结构。

增加一列

在表中增加一列的语句格式为:

ALTER TABLE 表名字 ADD COLUMN 列名字 数据类型 约束;
或:
ALTER TABLE 表名字 ADD 列名字 数据类型 约束;

现在 employee 表中有 id、name、age、salary、phone、in_dpt 这6个列,我们尝试加入 height (身高)一个列并指定DEFAULT 约束:

ALTER TABLE employee ADD height INT(4) DEFAULT 170;

2019-08-07-00-24-29.jpg

可以发现:新增加的列,被默认放置在这张表的最右边。如果要把增加的列插入在指定位置,则需要在语句的最后使用AFTER关键词(“AFTER 列1” 表示新增的列被放置在 “列1” 的后面)。

提醒:语句中的 INT(4) 不是表示整数的字节数,而是表示该值的显示宽度,如果设置填充字符为 0,则 170 显示为 0170

比如我们新增一列 weight(体重) 放置在 age(年龄) 的后面:

ALTER TABLE employee ADD weight INT(4) DEFAULT 120 AFTER age;

2019-08-07-00-28-27.jpg

上面的效果是把新增的列加在某位置的后面,如果想放在第一列的位置,则使用 FIRST 关键词,如语句:

ALTER TABLE employee ADD test INT(10) DEFAULT 11 FIRST;

2019-08-07-00-31-23.jpg

删除一列

删除表中的一列和刚才使用的新增一列的语句格式十分相似,只是把关键词 ADD 改为 DROP ,语句后面不需要有数据类型、约束或位置信息。具体语句格式:

ALTER TABLE 表名字 DROP COLUMN 列名字;

或: ALTER TABLE 表名字 DROP 列名字;

我们把刚才新增的 test 删除:

ALTER TABLE employee DROP test;

wm _2_.png

重命名一列

这条语句其实不只可用于重命名一列,准确地说,它是对一个列做修改(CHANGE) :

ALTER TABLE 表名字 CHANGE 原列名 新列名 数据类型 约束;

注意:这条重命名语句后面的 “数据类型” 不能省略,否则重命名失败。

原列名新列名相同的时候,指定新的数据类型约束,就可以用于修改数据类型或约束。需要注意的是,修改数据类型可能会导致数据丢失,所以要慎重使用。

我们用这条语句将 “height” 一列重命名为汉语拼音 “shengao” ,效果如下:

ALTER TABLE employee CHANGE height shengao INT(4) DEFAULT 170;

wm _3_.png

改变数据类型

要修改一列的数据类型,除了使用刚才的 CHANGE 语句外,还可以用这样的 MODIFY 语句:

ALTER TABLE 表名字 MODIFY 列名字 新数据类型;

再次提醒,修改数据类型必须小心,因为这可能会导致数据丢失。在尝试修改数据类型之前,请慎重考虑。

对表的内容修改

修改表中某个值

大多数时候我们需要做修改的不会是整个数据库或整张表,而是表中的某一个或几个数据,这就需要我们用下面这条命令达到精确的修改:

UPDATE 表名字 SET 列1=值1,列2=值2 WHERE 条件;

比如,我们要把 Tom 的 age 改为 21,salary 改为 3000:

UPDATE employee SET age=21,salary=3000 WHERE name=&#039;Tom&#039;;

wm _4_.png

注意:一定要有 WHERE 条件,否则会出现你不想看到的后果

删除一行记录

删除表中的一行数据,也必须加上 WHERE 条件,否则整列的数据都会被删除。删除语句:

DELETE FROM 表名字 WHERE 条件;

我们尝试把 Tom 的数据删除:

DELETE FROM employee WHERE name=&#039;Tom&#039;;

wm _5_.png

其他基本操作

学习并实践数据库的其它基本操作:索引、视图,导入和导出,备份和恢复等。

这些概念对于数据库管理员而言都非常重要,请仔细理解并完成所有实验操作。

作为基础篇,不会涉及到关于索引和视图的高级应用和核心概念,但是基本操作大家会了解,尤其是关于索引的内容,学会建立恰当的索引可以大大提高数据库的查询效率,更高级的应用我们会在进阶篇详细讲解。

  • 索引
  • 视图
  • 导入和导出
  • 备份和恢复

下载的代码会搭建好一个名为 mysql_shiyan 的数据库(有三张表:department,employee,project),并向其中插入数据。

git clone https://github.com/shiyanlou/SQL6

下载完成后,输入命令开启 MySQL 服务并使用 root 用户登录:

# 打开 MySQL 服务
sudo service mysql start

# 使用 root 用户登录
mysql -u root

下载的 SQL6 目录下,有两个文件 MySQL-06.sqlin.txt,其中第一个文件用于创建数据库并向其中插入数据,第二个文件用于测试数据导入功能。

索引

索引是一种与表有关的结构,它的作用相当于书的目录,可以根据目录中的页码快速找到所需的内容。

当表中有大量记录时,若要对表进行查询,没有索引的情况是全表搜索:将所有记录一一取出,和查询条件进行对比,然后返回满足条件的记录。这样做会执行大量磁盘 I/O 操作,并花费大量数据库系统时间。

而如果在表中已建立索引,在索引中找到符合查询条件的索引值,通过索引值就可以快速找到表中的数据,可以大大加快查询速度

对一张表中的某个列建立索引,有以下两种语句格式:

ALTER TABLE 表名字 ADD INDEX 索引名 (列名);

CREATE INDEX 索引名 ON 表名字 (列名);

我们用这两种语句分别建立索引:

ALTER TABLE employee ADD INDEX idx_id (id);  #在employee表的id列上建立名为idx_id的索引

CREATE INDEX idx_name ON employee (name);   #在employee表的name列上建立名为idx_name的索引

索引的效果是加快查询速度,当表中数据不够多的时候是感受不出它的效果的。这里我们使用命令 SHOW INDEX FROM 表名字; 查看刚才新建的索引:

SHOW INDEX FROM employee;

2019-08-07-15-14-43.jpg

在使用 SELECT 语句查询的时候,语句中 WHERE 里面的条件,会自动判断有没有可用的索引

比如有一个用户表,它拥有用户名(username)和个人签名(note)两个字段。其中用户名具有唯一性,并且格式具有较强的限制,我们给用户名加上一个唯一索引;个性签名格式多变,而且允许不同用户使用重复的签名,不加任何索引。

这时候,如果你要查找某一用户,使用语句 select * from user where username=?select * from user where note=?性能是有很大差距的,对建立了索引的用户名进行条件查询会比没有索引的个性签名条件查询快几倍,在数据量大的时候,这个差距只会更大。

一些字段不适合创建索引,比如性别,这个字段存在大量的重复记录无法享受索引带来的速度加成,甚至会拖累数据库,导致数据冗余和额外的 CPU 开销。

视图

视图是从一个或多个表中导出来的表,是一种虚拟存在的表。它就像一个窗口,通过这个窗口可以看到系统专门提供的数据,这样,用户可以不用看到整个数据库中的数据,而只关心对自己有用的数据。

注意理解视图是虚拟的表:

  • 数据库中只存放了视图的定义,而没有存放视图中的数据,这些数据存放在原来的表中;
  • 使用视图查询数据时,数据库系统会从原来的表中取出对应的数据;
  • 视图中的数据依赖于原来表中的数据,一旦表中数据发生改变,显示在视图中的数据也会发生改变;
  • 在使用视图的时候,可以把它当作一张表。

创建视图的语句格式为:

CREATE VIEW 视图名(列a,列b,列c) AS SELECT 列1,列2,列3 FROM 表名字;

可见创建视图的语句,后半句是一个 SELECT 查询语句,所以视图也可以建立在多张表上,只需在 SELECT 语句中使用子查询连接查询,这些在之前的实验已经进行过。

现在我们创建一个简单的视图,名为 v_emp,包含v_namev_agev_phone三个列:

CREATE VIEW v_emp (v_name,v_age,v_phone) AS SELECT name,age,phone FROM employee;

wm.png

导入

此处讲解的是导入一个纯数据文件,该文件中将包含与数据表字段相对应的多条数据,这样可以快速导入大量数据,除此之外,还有用 SQL 语句的导入方式,语法为:source *.sql 这是实验中经常用到的。两者之间的不同是:数据文件导入方式只包含数据,导入规则由数据库系统完成;SQL 文件导入相当于执行该文件中包含的 SQL 语句,可以实现多种操作,包括删除,更新,新增,甚至对数据库的重建。

数据文件导入,可以把一个文件里的数据保存进一张表。导入语句格式为:

LOAD DATA INFILE &#039;文件路径和文件名&#039; INTO TABLE 表名字;

现在 SQL6 目录下有一个名为 in.txt 的文件,我们尝试把这个文件中的数据导入数据库 mysql_shiyanemployee 表中。

由于导入导出大量数据都属于敏感操作,根据 mysql 的安全策略,导入导出的文件都必须在指定的路径下进行,在 mysql 终端中查看路径变量:

mysql -uroot
mysql&gt; show variables like &#039;%secure%&#039;;
+--------------------------+-----------------------+
| Variable_name            | Value                 |
+--------------------------+-----------------------+
| require_secure_transport | OFF                   |
| secure_auth              | ON                    |
| secure_file_priv         | /var/lib/mysql-files/ |
+--------------------------+-----------------------+
3 rows in set (0.00 sec)

注意到 secure_file_priv 变量指定安全路径为 /var/lib/mysql-files/ ,要导入数据文件,需要将该文件移动到安全路径下。

打开 Xfce 终端,输入命令拷贝 SQL6 文件夹到 /var/lib/mysql-files/ 目录:

sudo cp -a /home/shiyanlou/Desktop/SQL6 /var/lib/mysql-files/

使用命令 sudo vim /var/lib/mysql-files/SQL6/in.txt 查看 in.txt 文件中的内容:

2019-08-07-15-38-05.jpg

可以看到其中仅仅包含了数据本身,没有任何的 SQL 语句

再使用以下命令以 root 用户登录数据库,再连接 mysql_shiyan 数据库:

# 在Xfce 终端输入命令
mysql -u root

# 在 MySQL 控制台中输入命令
use mysql_shiyan

查看一下没有导入数据之前,employee 表中的数据:

2019-08-07-15-45-49.jpg

现在执行导入语句,文件中的数据成功导入 employee 表:

wm _1_.png

导出

导出与导入是相反的过程,是把数据库某个表中的数据保存到一个文件之中。导出语句基本格式为:

SELECT 列1,列2 INTO OUTFILE &#039;文件路径和文件名&#039; FROM 表名字;

注意:语句中 “文件路径” 之下不能已经有同名文件。

现在我们把整个 employee 表的数据导出到 /var/lib/mysql-files/ 目录下,导出文件命名为 out.txt 具体语句为:

SELECT * INTO OUTFILE &#039;/var/lib/mysql-files/out.txt&#039; FROM employee;

用 gedit 可以查看导出文件 /var/lib/mysql-files/out.txt 的内容:

也可以使用 sudo cat /var/lib/mysql-files/out.txt 命令查看。

wm _2_.png

备份

数据库中的数据十分重要,出于安全性考虑,在数据库的使用中,应该注意使用备份功能。

备份与导出的区别:导出的文件只是保存数据库中的数据;而备份,则是把数据库的结构,包括数据、约束、索引、视图等全部另存为一个文件。

mysqldump 是 MySQL 用于备份数据库的实用程序。它主要产生一个 SQL 脚本文件,其中包含从头重新创建数据库所必需的命令 CREATE TABLE INSERT 等。

使用 mysqldump 备份的语句:

mysqldump -u root 数据库名&gt;备份文件名;   #备份整个数据库

mysqldump -u root 数据库名 表名字&gt;备份文件名;  #备份整个表

mysqldump 是一个备份工具,因此该命令是在终端中执行的,而不是在 mysql 交互环境下

我们尝试备份整个数据库 mysql_shiyan,将备份文件命名为 bak.sql,先 Ctrl+D 退出 MySQL 控制台,再打开 Xfce 终端,在终端中输入命令:

cd /home/shiyanlou/
mysqldump -u root mysql_shiyan &gt; bak.sql;

使用命令 “ls” 可见已经生成备份文件 bak.sql

wm _3_.png

你可以用 gedit 查看备份文件的内容,可以看见里面不仅保存了数据,还有所备份的数据库的其它信息。

恢复

用备份文件恢复数据库,其实我们早就使用过了。在本次实验的开始,我们使用过这样一条命令:

source /tmp/SQL6/MySQL-06.sql

这就是一条恢复语句,它把 MySQL-06.sql 文件中保存的mysql_shiyan 数据库恢复。

还有另一种方式恢复数据库,但是在这之前我们先使用命令新建一个空的数据库 test

mysql -u root          #因为在上一步已经退出了MySQL,现在需要重新登录

CREATE DATABASE test;  #新建一个名为test的数据库

再次 Ctrl+D 退出 MySQL,然后输入语句进行恢复,把刚才备份的 bak.sql 恢复到 test 数据库:

mysql -u root test &lt; bak.sql

我们输入命令查看 test 数据库的表,便可验证是否恢复成功:

mysql -u root          #因为在上一步已经退出了MySQL,现在需要重新登录

use test               #连接数据库test

SHOW TABLES;           #查看test数据库的表

可以看见原数据库的4张表和1个视图,现在已经恢复到 test 数据库中:

wm.png

再查看 employee 表的恢复情况:

wm.png

在本实验中,我们实践了下面几个基本概念:

  1. 索引:可以加快查询速度
  2. 视图:是一种虚拟存在的表
  3. 导入:从文件中导入数据到表
  4. 导出:从表中导出到文件中
  5. 备份:mysqldump 备份数据库到文件
  6. 恢复:从文件恢复数据库

示例

建立员工名字 employee.name 和对应部门人数 department.people_num 的视图并展示。

mysql&gt; CREATE VIEW name_people_num (name, people_num)
    -&gt; AS SELECT name, people_num FROM employee, department
    -&gt; WHERE in_dpt = dpt_name;
Query OK, 0 rows affected (0.01 sec)

mysql&gt; SELECT * FROM name_people_num;
+------+------------+
| name | people_num |
+------+------------+
| Alex |         11 |
| Ken  |         11 |
| Mike |         11 |
| Jack |         12 |
| Jobs |         12 |
| Joe  |         12 |
| Mary |         12 |
| Tony |         10 |
| Rose |         10 |
| Rick |         10 |
| Tom  |         15 |
| Jim  |         15 |
+------+------------+
12 rows in set (0.00 sec)