一、数据库概述
1、什么是数据库?
-
**定义**:数据库(Database, DB)是按照数据结构来组织、存储和管理数据的仓库,用于高效存储、检索和管理大量结构化或非结构化数据。
-
**核心目标**:解决数据冗余、数据不一致性问题,确保数据的安全性、完整性和可访问性
2、数据库管理系统(DBMS)
-
**定义**:数据库管理系统是用于管理数据库的软件系统,负责数据的存储、查询、更新、删除等操作,并提供事务管理、权限控制、备份恢复等功能。
-
常见 DBMS:
-
**关系型数据库**:MySQL、PostgreSQL、Oracle、SQL Server。
-
**非关系型数据库(NoSQL)**:MongoDB、Redis、Cassandra。
3、数据库分类
数据库主要分为**关系型数据库**和 ** 非关系型数据库(NoSQL)** 两大类,两者在数据模型、适用场景上有显著差异。
```
姓名 年纪 地址 性别 出生
张三 18 china man 1990
张三
```
**关系型数据库(SQL)**
-
**数据模型**:基于二维表格(关系表),通过行(记录)和列(字段)存储数据,表间通过主键、外键建立关联。
-
特点:
-
结构化强,数据一致性高。
-
支持复杂查询(如 JOIN、子查询),适合事务性场景(如金融交易、订单系统)。
-
遵循 ACID 特性(原子性、一致性、隔离性、持久性)。
-
**典型应用**:企业 ERP 系统、银行核心系统、电商订单管理。
** 非关系型数据库(NoSQL)**
-
**数据模型**:采用键值对、文档、列族、图结构等非表格模型存储数据。
-
特点:
-
灵活可扩展,适合处理海量非结构化数据(如日志、图片、JSON 文档)。
-
读写性能高,支持分布式架构。
-
弱化 ACID,强调 BASE 特性(基本可用、软状态、最终一致性)。
-
细分类型及示例:
-
**键值存储**:Redis(用于缓存、会话管理)。
-
**文档存储**:MongoDB(用于内容管理、用户数据存储)。
-
**列族存储**:HBase(用于海量数据实时查询,如日志分析)。
-
**图存储**:Neo4j(用于社交网络、推荐系统中的关系分析)。
-
**典型应用**:互联网用户行为分析、实时推荐系统、物联网设备数据存储。
4、结构化查询语言(SQL)
结构化查询语言(SQL)是用于管理和操作关系型数据库的标准编程语言,广泛应用于数据存储、查询、更新和管理。以下是对 SQL 的详细解析:
**. 定义与作用**
-
**SQL(Structured Query Language)**:是一种专门设计用于与数据库通信的编程语言,用于执行数据操作(如查询、插入、更新)和数据库管理(如创建表、修改结构、权限控制)。
-
核心功能:
-
数据查询(SELECT):从数据库中检索数据。
-
数据操作(INSERT、UPDATE、DELETE):增删改数据。
-
数据定义(CREATE、ALTER、DROP):创建、修改、删除数据库对象(如表、索引)。
-
数据控制(GRANT、REVOKE):管理用户权限。
**SQL 与数据库的关系**
- SQL 是一种语言标准,而数据库(如 MySQL、PostgreSQL、Oracle)是实现 SQL 标准的软件系统。不同数据库对 SQL 的支持略有差异,但核心语法一致。
二、MySQL入门
```
MySQL是一个c/s架构的软件
c/s: client (客户端)------> server 服务端 代表应用:QQ 迅雷 企业微信
b/s: browser (浏览器) ----> server 服务端
密码:qwe123 输入的时候要是英文状态,然后必须是小写。
```
MySQL 是全球最流行的开源关系型数据库管理系统(RDBMS),由瑞典 MySQL AB 公司开发,后被 Oracle 收购。它以高性能、可靠性和易用性著称,广泛应用于 Web 应用、企业系统和中小型数据存储场景。以下是对 MySQL 的深度解析:
1、核心特性
开源与跨平台
-
**开源许可证**:采用 GPL(通用公共许可证),允许免费使用和修改,但商业应用需购买商业许可证。
-
**跨平台支持**:支持 Linux、Windows、macOS、Solaris 等主流操作系统。
** 存储引擎**
MySQL 支持多种存储引擎,每个引擎有不同特性,最常用的是:
-
**InnoDB**(默认):支持事务、外键、行级锁和崩溃恢复,适合高并发和写密集型场景。
-
**MyISAM**:不支持事务和外键,读写性能高,但不适合高并发事务场景。
-
**Memory**:数据存储在内存中,查询极快,适合临时数据或缓存。
-
**Archive**:只支持 INSERT 和 SELECT,压缩率高,适合历史数据归档。
**高性能与扩展性**
-
**索引优化**:支持 B-Tree、哈希索引,优化查询效率。
-
**复制(Replication)**:主从复制、主主复制,实现读写分离和高可用性。
-
**分区(Partitioning)**:水平分割大表,提升查询性能。
**安全与权限管理**
-
**用户认证**:基于用户名、主机和密码的访问控制。
-
**细粒度权限**:支持 GRANT/REVOKE 对数据库、表、列级别的权限控制。
-
**加密功能**:支持 SSL/TLS 加密传输,以及数据静态加密(TDE)。
2、MySQL链接
安装 MySQL 后,你可以通过以下几种方式连接到 MySQL 服务端:
-
1、使用命令行客户端连接
-
2、使用图形化工具连接
常用 MySQL 图形化管理工具:
-
MySQL Workbench(官方工具):https://www.mysql.com/cn/products/workbench/
-
Navicat(付费):https://www.navicat.com/
-
DBeaver:https://dbeaver.io/
-
phpMyAdmin(基于Web):https://www.phpmyadmin.net/
使用MySQL命令行链接
```
mysql -u your_username -p
```
**参数说明:**
-
`-u` 参数用于指定用户名。
-
`-p` 参数表示需要输入密码。
指定主机和端口连接(适用于远程连接):
```
mysql -h 主机名或IP地址 -P 端口号 -u 用户名 -p
```
例如:
```
mysql -h 127.0.0.1 -P 3306 -u root -p
```
3、简单的SQL语句
列出所有可用的数据库:
```
SHOW DATABASES;
```
选择要使用的数据库:
```
USE your_database;
```
列出所选数据库中的所有表:
```
SHOW TABLES;
```
退出 **mysql>** 命令提示窗口可以使用 **exit** 命令,如下所示:
```
mysql> EXIT;
Bye
```
或者使用:
```
mysql> QUIT;
```
或者按下 **Ctrl + D**(在 Unix/Linux 系统中)。
4、创建数据库
我们可以在登陆 MySQL 服务后,使用 **create** 命令创建数据库,语法如下:
```
CREATE DATABASE 数据库名;
```
以下命令简单的演示了创建数据库的过程,数据名为 helloworld:
```
root@host# mysql -u root -p
Enter password:****** # 登录后进入终端
mysql> create DATABASE helloworld;
```
建数据库的基本语法如下:
```
CREATE DATABASE IF NOT EXISTS database_name
CHARACTER SET charset_name
COLLATE collation_name;
```
如果你希望在创建数据库时指定一些选项,可以使用 CREATE DATABASE 语句的其他参数,例如,你可以指定字符集和排序规则:
```
CREATE DATABASE mydatabase
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;
```
如果数据库已经存在,执行 CREATE DATABASE 将导致错误。
为了避免这种情况,你可以在 CREATE DATABASE 语句中添加 IF NOT EXISTS 子句:
```
CREATE DATABASE IF NOT EXISTS mydatabase;
```
5、删除数据库
使用普通用户登陆 MySQL 服务器,你可能需要特定的权限来创建或者删除 MySQL 数据库,所以我们这边使用 root 用户登录,root 用户拥有最高权限。
在删除数据库过程中,务必要十分谨慎,因为在执行删除命令后,所有数据将会消失。
**drop 命令删除数据库**
drop 命令格式:
```
DROP DATABASE <database_name>; -- 直接删除数据库,不检查是否存在
或
DROP DATABASE IF EXISTS <database_name>;
```
**参数说明:**
-
`IF EXISTS` 是一个可选的子句,表示如果数据库存在才执行删除操作,避免因为数据库不存在而引发错误。
-
`database_name` 是你要删除的数据库的名称。
例如删除名为 helloworld 的数据库:
```
-- 直接删除数据库,不检查是否存在
mysql> DROP DATABASE helloworld;
-- 删除数据库,如果存在的话
DROP DATABASE IF EXISTS helloworld;
```
**注意:** 在执行删除数据库操作前,请确保你确实想要删除数据库及其所有数据,因为该操作是不可逆的。为了避免误操作,通常建议在执行删除之前备份数据库。
**6、创建数据表**
**语法**
以下为创建 MySQL 数据表的 SQL 通用语法:
```
CREATE TABLE table_name (
column1 datatype,
column2 datatype,
...
);
create table goods(
name varchar(50),
price decimal(10, 2),
description varchar(500),
address varchar(100)
)charset=utf8;
create table goods()charset=utf8;
添加数据:
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
insert into goods(name,price,description,address) values("小米 suv7", 10000.01, "are you ok", "beijing");
insert into goods(name,price,description,address) values("小米 Ultra", 100000.01, "are you ok", "beijing");
```
**参数说明:**
-
`table_name` 是你要创建的表的名称。
-
`column1`, `column2`, ... 是表中的列名。
-
`datatype` 是每个列的数据类型。
以下是一个具体的实例,创建一个用户表 **users**:
```
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
birthdate DATE,
is_active BOOLEAN DEFAULT TRUE
);
```
实例解析:
-
`id`: 用户 id,整数类型,自增长,作为主键。
-
`username`: 用户名,变长字符串,不允许为空。
-
`email`: 用户邮箱,变长字符串,不允许为空。
-
`birthdate`: 用户的生日,日期类型。
-
`is_active`: 用户是否已经激活,布尔类型,默认值为 true。
7、删除数据表
语法
以下为删除 MySQL 数据表的通用语法:
```
DROP TABLE table_name; -- 直接删除表,不检查是否存在
```
或
```
DROP TABLE IF EXISTS table_name; -- 会检查是否存在,如果存在则删除
```
**参数说明:**
-
`table_name` 是要删除的表的名称。
-
`IF EXISTS` 是一个可选的子句,表示如果表存在才执行删除操作,避免因为表不存在而引发错误。
```
-- 删除表,如果存在的话
DROP TABLE IF EXISTS mytable;
-- 直接删除表,不检查是否存在
DROP TABLE mytable;
```
8、插入数据
语法
以下为向MySQL数据表插入数据通用的 **INSERT INTO** SQL语法:
```
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
```
**参数说明:**
-
`table_name` 是你要插入数据的表的名称。
-
`column1`, `column2`, `column3`, ... 是表中的列名。
-
`value1`, `value2`, `value3`, ... 是要插入的具体数值。
如果数据是字符型,必须使用单引号 **'** 或者双引号 **"**,如: 'value1', "value1"。
一个简单的实例,插入了一行数据到名为 users 的表中:
```
INSERT INTO users (username, email, birthdate, is_active)
VALUES ('test', 'test@google.com', '1990-01-01', true);
```
-
`username`: 用户名,字符串类型。
-
`email`: 邮箱地址,字符串类型。
-
`birthdate`: 用户生日, 日期类型。
-
`is_active`: 是否已激活,布尔类型。
如果你要插入所有列的数据,可以省略列名:
```
INSERT INTO users
VALUES (NULL,'test', 'test@google.com', '1990-01-01', true);
```
这里,**NULL** 是用于自增长列的占位符,表示系统将为 **id** 列生成一个唯一的值。
如果你要插入多行数据,可以在 VALUES 子句中指定多组数值:
```
INSERT INTO users (username, email, birthdate, is_active)
VALUES
('test1', 'test1@google.com', '1985-07-10', true),
('test2', 'test2@google.com', '1988-11-25', false),
('test3', 'test3@google.com', '1993-05-03', true);
```
以上代码将在 users 表中插入三行数据。
查询数据:
语法:
```
SELECT COLUMN1,COLUMN2...... FROM TABLE_NAME; 显示指定字段
SELECT * FROM TABLE_NAME; 显示所有字段
```
修改数据:
语法:
```
UPDATE TABLE_NAME SET COLUMN=VALUE; 将某一列里面的所有数据都更新
UPDATE TABLE_NAME SET COLUMN=VALUE WHERE 条件;
```
9、表结构修改
- 添加列
```
ALTER TABLE 表名
ADD COLUMN 列名 数据类型 约束条件 AFTER 现有列名\|FIRST;
```
示例:
```
-- 在users表的email列后添加age列
ALTER TABLE users
ADD COLUMN age INT NOT NULL DEFAULT 0 AFTER email;
-- 添加多列
ALTER TABLE users
ADD COLUMN phone VARCHAR(20),
ADD COLUMN address VARCHAR(100);
```
- 删除列
```
ALTER TABLE 表名
DROP COLUMN 列名;
```
示例:
```
ALTER TABLE users
DROP COLUMN age;
```
- 修改列定义
```
ALTER TABLE 表名
MODIFY COLUMN 列名 新数据类型 新约束条件;
```
示例:
```
-- 修改username长度并添加唯一约束
ALTER TABLE users
MODIFY COLUMN username VARCHAR(50) UNIQUE;
-- 修改列默认值
ALTER TABLE users
MODIFY COLUMN status TINYINT DEFAULT 1;
```
- 重命名列
```
ALTER TABLE 表名
CHANGE COLUMN 旧列名 新列名 数据类型 约束条件;
```
示例:
```
ALTER TABLE users
CHANGE COLUMN reg_date register_date DATETIME;
```
三、MySQL数据类型
MySQL 中定义数据字段的类型对你数据库的优化是非常重要的。
MySQL 支持多种类型,大致可以分为三类:数值、日期/时间和字符串(字符)类型。
1、数值类型
MySQL 支持所有标准 SQL 数值数据类型。
这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL 和 NUMERIC),以及近似数值数据类型(FLOAT、REAL 和 DOUBLE PRECISION)。
关键字INT是INTEGER的同义词,关键字DEC是DECIMAL的同义词。
BIT数据类型保存位字段值,并且支持 MyISAM、MEMORY、InnoDB 和 BDB表。
作为 SQL 标准的扩展,MySQL 也支持整数类型 TINYINT、MEDIUMINT 和 BIGINT。下面的表显示了需要的每个整数类型的存储和范围。
| 类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
| :----------- | :--------------------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | :-------------- |
| TINYINT | 1 Bytes | (-128,127) | (0,255) | 小整数值 |
| SMALLINT | 2 Bytes | (-32 768,32 767) | (0,65 535) | 大整数值 |
| MEDIUMINT | 3 Bytes | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
| INT或INTEGER | 4 Bytes | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
| BIGINT | 8 Bytes | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值 |
| FLOAT | 4 Bytes | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 单精度 浮点数值 |
| DOUBLE | 8 Bytes | (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 双精度 浮点数值 |
| DECIMAL | 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 | 依赖于M和D的值 | 依赖于M和D的值 | 小数值 |
```
create table demo1(
name varchar(50),
age tinyint unsigned
);
create table demo2(
name varchar(50),
age int
);
create table demo3(
goods_name varchar(50),
price decimal(10, 2)
);
```
2、日期和时间类型
表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。
每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。
TIMESTAMP类型有专有的自动更新特性,将在后面描述。
| 类型 | 大小 ( bytes) | 范围 | 格式 | 用途 |
| :-------- | :------------ | :----------------------------------------------------------- | :------------------ | :----------------------- |
| DATE | 3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 |
| TIME | 3 | '-838:59:59'/'838:59:59' | HH:MM:SS | 时间值或持续时间 |
| YEAR | 1 | 1901/2155 | YYYY | 年份值 |
| DATETIME | 8 | '1000-01-01 00:00:00' 到 '9999-12-31 23:59:59' | YYYY-MM-DD hh:mm:ss | 混合日期和时间值 |
| TIMESTAMP | 4 | '1970-01-01 00:00:01' UTC 到 '2038-01-19 03:14:07' UTC结束时间是第 **2147483647** 秒,北京时间 **2038-1-19 11:14:07**,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYY-MM-DD hh:mm:ss | 混合日期和时间值,时间戳 |
```
create table demo4(
title varchar(100),
add_time DATE
);
create table demo5(
title varchar(100),
add_time year
);
```
3、字符串类型
字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。该节描述了这些类型如何工作以及如何在查询中使用这些类型。
| 类型 | 大小 | 用途 |
| :--------- | :-------------------- | :------------------------------ |
| CHAR | 0-255 bytes | 定长字符串 |
| VARCHAR | 0-65535 bytes | 变长字符串 |
| TINYBLOB | 0-255 bytes | 不超过 255 个字符的二进制字符串 |
| TINYTEXT | 0-255 bytes | 短文本字符串 |
| BLOB | 0-65 535 bytes | 二进制形式的长文本数据 |
| TEXT | 0-65 535 bytes | 长文本数据 |
| MEDIUMBLOB | 0-16 777 215 bytes | 二进制形式的中等长度文本数据 |
| MEDIUMTEXT | 0-16 777 215 bytes | 中等长度文本数据 |
| LONGBLOB | 0-4 294 967 295 bytes | 二进制形式的极大文本数据 |
| LONGTEXT | 0-4 294 967 295 bytes | 极大文本数据 |
**注意**:char(n) 和 varchar(n) 中括号中 n 代表字符的个数,并不代表字节个数,比如 CHAR(30) 就可以存储 30 个字符。
CHAR 和 VARCHAR 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。
BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。
BLOB 是一个二进制大对象,可以容纳可变数量的数据。有 4 种 BLOB 类型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。
有 4 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4 种 BLOB 类型,可存储的最大长度不同,可根据实际情况选择。
```
create table demo1(
name char(10)
);
create table demo2(
title varchar(100)
);
create table demo3(
content LONGTEXT
);
```
四、字段约束
在数据库中,字段约束(也称为列约束)是一种规则,用于限制可以存储在表字段中的数据类型、范围或格式。它们确保数据的完整性和一致性,防止无效或不符合业务规则的数据进入数据库。
1、非空约束(not null)
**作用**:字段必须包含值,插入 `NULL` 会报错。
示例:
```
CREATE TABLE users (
name VARCHAR(50) NOT NULL, -- 姓名不能为空
email VARCHAR(50),
);
```
2、唯一约束(**UNIQUE**)
作用:字段值必须唯一,但可以为 `NULL`(多个 `NULL` 被视为相同)。
示例:
```
CREATE TABLE users2 (
email VARCHAR(50) UNIQUE -- 邮箱不能重复
);
```
3、主键约束(**PRIMARY KEY**)
作用:唯一标识表中的记录,隐含 `NOT NULL + UNIQUE`。
示例:
```
CREATE TABLE products (
product_id INT PRIMARY KEY, -- 单字段主键
name VARCHAR(50)
);
-- 复合主键(多个字段组合唯一)
CREATE TABLE order_items (
order_id INT,
product_id INT,
PRIMARY KEY (order_id, product_id)
);
create table wenzhang2(
id int AUTO_INCREMENT primary key,
title varchar(200) UNIQUE not null,
author varchar(50) not null,
address varchar(100) not null,
add_time datetime not null,
content longtext not null
);
insert into wenzhang(id,title, author,address,add_time,content)
values(1, "python 从入门到精通", "zhangsan", "beijing", "2025-5-23 20:59:01", "python nice!")
insert into wenzhang2(title,author,address,add_time,content)
values("python 从入门到精通", "zhangsan", "beijing", "2025-5-23 20:59:01", "python nice!");
```
4、默认约束(**DEFAULT**)
作用:当插入数据未提供值时,自动使用默认值。
```
CREATE TABLE logs (
id INT PRIMARY KEY,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 默认当前时间
);
create table demo5(
name varchar(50) not null,
age int not null
);
```
5、自动增长(AUTO_INCREMENT)
在 MySQL 中,`AUTO_INCREMENT` 是一种特殊的字段属性,用于为表中的记录生成唯一的自增数值。它通常与主键(PRIMARY KEY)一起使用,确保每条记录都有一个唯一标识.
**创建表时指定 `AUTO_INCREMENT`**
```
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT, -- 自增主键
name VARCHAR(50) NOT NULL,
email VARCHAR(50) UNIQUE
);
```
-
无需手动插入 `id` 值,MySQL 会自动生成下一个可用的整数。
-
初始值默认为 `1`,每次插入新记录时递增 `1`。
**起始值与步长**
- **起始值**:默认从 `1` 开始,可通过 `ALTER TABLE` 修改:
```
ALTER TABLE users AUTO_INCREMENT = 100; -- 下一个插入的id为100
```
- **步长**:通常为 `1`,不支持直接设置步长(由 MySQL 内部控制)。
**处理删除操作**
若删除某条记录,自增序列不会回退。例如:
```
DELETE FROM users WHERE id = 2; -- 删除id=2的记录
INSERT INTO users (name, email) VALUES ('Charlie', 'charlie@example.com');
-- 新记录的id=3(而非2)
```
**手动插入自增字段**
可以手动指定 `id` 值,但需确保不与现有值冲突:
```
INSERT INTO users (id, name, email) VALUES (10, 'David', 'david@example.com');
-- 强制使用id=10,下一个自动生成的id为11
```
6、注释(comment)
在 MySQL 中,注释(**COMMENT**)是一种用于为表、列(字段)、存储过程等数据库对象添加说明文字的机制。它不会影响数据库的功能,但能帮助开发者理解表结构和数据含义。
**列(字段)注释**
为表中的字段添加描述性信息,便于后续维护。
```
CREATE TABLE usersss (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID,自增主键',
name VARCHAR(50) NOT NULL COMMENT '用户姓名',
email VARCHAR(50) UNIQUE COMMENT '用户邮箱,唯一标识'
);
```
查看列注释:
```
SHOW FULL COLUMNS FROM users;
```
**表注释**
为整个表添加说明,解释其用途和数据范围。
```
CREATE TABLE products (
product_id INT PRIMARY KEY,
name VARCHAR(50)
) COMMENT = '存储所有商品的基础信息,包括名称、价格等';
```
查看表注释:
```
SHOW CREATE TABLE products;
```
五、数据表关系
在 MySQL 中,表关系(Table Relationships)用于建立不同数据表之间的关联,使数据能够以结构化方式组织和查询。常见的表关系包括**一对一**、**一对多**和**多对多**,这些关系通过外键实现。
1、 **一对一关系(One-to-One)**
**特点**
-
**一个记录仅对应另一个表中的一个记录**:例如,一个用户(User)只有一个详细资料(Profile)。
-
**实现方式**:在任意一方添加唯一外键,指向另一方的主键。
```sql
-- 用户表
CREATE TABLE users (
user_id INT PRIMARY KEY,
username VARCHAR(50)
);
-- 资料表
CREATE TABLE profiles (
profile_id INT PRIMARY KEY,
address VARCHAR(100),
user_id INT UNIQUE, -- 唯一外键,关联users表的user_id
);
create table student(
id int unsigned auto_increment comment "主键",
name varchar(50) not null comment "学生的名字",
age tinyint unsigned not null comment "学生的年纪",
sex tinyint unsigned not null default 1 comment "1代表男,0代表女",
primary key(id)
);
create table student_profile(
height tinyint unsigned not null comment "学生的身高",
id_num char(18) unique not null comment "学生的身份证号码",
student_id int unsigned not null comment "存储学生的id"
);
张三 18 1 182 23412341234123412341234
```
2、**一对多关系(One-to-Many)**
**特点**
-
**一个记录对应多个记录**:例如,一个部门(Department)可以有多个员工(Employee)。
-
**实现方式**:在 "多" 的一方表中添加外键,指向 "一" 的一方的主键。
```sql
-- 部门表(一)
CREATE TABLE departments (
dept_id INT PRIMARY KEY,
dept_name VARCHAR(50)
);
-- 员工表(多)
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(50),
dept_id INT, -- 外键,关联departments表的dept_id
);
create table department(
id int unsigned auto_increment comment "主键",
dept_name varchar(50) not null comment "部门的名称",
leader varchar(50) not null comment "部门领导",
information text not null comment "部门介绍",
primary key(id)
);
insert into department(dept_name, leader, information) values("人事部", "zhangsan", "adfadsadfadsfsaddf");
insert into department(dept_name, leader, information) values("财务部", "lisi", "adfadsadfadsfsaddf");
create table employees(
id int unsigned auto_increment comment "主键",
name varchar(50) not null comment "员工的名称",
salary int unsigned not null comment "员工的工资",
department_id int unsigned not null comment "部门的id",
primary key(id)
);
insert into employees(name, salary, department_id) values("小红", 8000, 1);
insert into employees(name, salary, department_id) values("小花", 9000, 1);
```
3、**多对多关系(Many-to-Many)**
**特点**
-
**多个记录对应多个记录**:例如,一个学生(Student)可以选修多门课程(Course),一门课程也可以被多个学生选修。
-
**实现方式**:通过创建中间表(关联表),将多对多拆分为两个一对多关系。
```sql
-- 学生表
CREATE TABLE students (
student_id INT PRIMARY KEY,
student_name VARCHAR(50)
);
-- 课程表
CREATE TABLE courses (
course_id INT PRIMARY KEY,
course_name VARCHAR(50)
);
-- 中间表(关联表)
CREATE TABLE student_courses (
student_id INT,
course_id INT,
);
学生管理系统:
create table student2(
id int unsigned auto_increment comment "主键",
name varchar(50) not null comment "学生的名称",
age tinyint unsigned not null comment "学生的年纪",
sex tinyint unsigned not null default 1 comment "1代表男,0代表女",
courses varchar(500) not null comment "学习选择的课程",
primary key(id)
);
insert into student2(name,age,sex, courses) values(
"小红", 18, 1, "1|2|3"
);
================================== 优化版 =======================================
create table student3(
id int unsigned auto_increment comment "主键",
name varchar(50) not null comment "学生的名称",
age tinyint unsigned not null comment "学生的年纪",
sex tinyint unsigned not null default 1 comment "1代表男,0代表女",
primary key(id)
);
insert into student3(name,age,sex, courses) values(
"小红", 18, 1
);
insert into student3(name,age,sex, courses) values(
"小花", 18, 0
);
小红id: 1
小花id: 2
create table student_course(
student_id int unsigned not null comment "学生id",
course_id int unsigned not null comment "课程id",
);
insert into student_course(student_id, course_id) values(1, 1); 小红 计算机组成原理
insert into student_course(student_id, course_id) values(1, 2); 小红 操作系统
insert into student_course(student_id, course_id) values(1, 3); 小红 数据库理论
insert into student_course(student_id, course_id) values(2, 2); 小花 操作系统
insert into student_course(student_id, course_id) values(2, 3); 小花 数据库理论
create table course(
id int unsigned auto_increment comment "主键",
course_name varchar(50) not null comment "课程的名称",
course_count int unsigned not null comment "课时",
primary key(id)
);
insert into course(course_name, course_count) values("计算机组成原理", 150); 1
insert into course(course_name, course_count) values("操作系统", 140); 2
insert into course(course_name, course_count) values("数据库理论", 30); 3
```
六、查询
1. 条件
使用where子句对表中的数据筛选,结果为true的行会出现在结果集中
- 语法如下:
```sql
select * from 表名 where 条件;
例:
select * from students where id=1;
create table student(
id int unsigned auto_increment comment "主键",
name varchar(50) not null comment "学生的名称",
age tinyint unsigned not null comment "学生的年纪",
gender tinyint unsigned not null default 1 comment "学生的性别,1代表男,0代表女",
height tinyint unsigned not null comment "学生的身高",
address varchar(500) not null comment "地址",
primary key(id)
);
insert into student(name,age,gender,height,address) values("小红", 18, 0, 182, "北京");
insert into student(name,age,gender,height,address) values("小花", 19, 0, 170, "长沙");
insert into student(name,age,gender,height,address) values("小绿", 20, 1, 160, "深圳");
insert into student(name,age,gender,height,address) values("小明", 30, 0, 182, "上海");
insert into student(name,age,gender,height,address) values("大明", 40, 1, 190, "新疆");
insert into student(name,age,gender,height,address) values("二明", 35, 1, 187, "西藏");
insert into student(name,age,gender,height,address) values("小蓝", 16, 0, 150, "长沙");
insert into student(name,age,gender,height,address) values("小紫", 16, 0, 150, "长沙");
insert into student(name,age,gender,height,address) values("大牛", 16, 1, 150, "上海");
insert into student(name,age,gender,height,address) values("如花", 16, 3, 150, "上海");
insert into student(name,age,gender,height,address) values("凤姐", 25, 0, 150, "上海");
```
-
where后面支持多种运算符,进行条件的处理
-
比较运算符
-
逻辑运算符
-
模糊查询
-
范围查询
-
空判断
比较运算符
-
等于: =
-
大于: >
-
大于等于: >=
-
小于: <
-
小于等于: <=
-
不等于: != 或 <>
例1:查询编号大于3的学生
```sql
select * from students where id > 3;
```
例2:查询编号不大于4的学生
```sql
select * from students where id <= 4;
```
例3:查询姓名不是"黄蓉"的学生
```sql
select * from students where name != '黄蓉';
```
例4:查询没被删除的学生
```sql
select * from students where is_delete=0;
```
逻辑运算符
-
and
-
or
-
not
例5:查询编号大于3的女同学
```sql
select * from students where id > 3 and gender=0;
```
例6:查询编号小于4或没被删除的学生
```sql
select * from students where id < 4 or is_delete=0;
```
模糊查询
-
like
-
%表示任意多个任意字符
-
%
-
_表示一个任意字符
例7:查询姓黄的学生
```sql
select * from students where name like '黄%';
```
例8:查询姓黄并且"名"是一个字的学生
```sql
select * from students where name like '黄_';
```
例9:查询姓黄或叫靖的学生
```sql
select * from students where name like '黄%' or name like '%靖';
```
范围查询
- in表示在一个非连续的范围内
例10:查询编号是1或3或8的学生
```sql
select * from students where id in(1,3,8);
```
- between ... and ...表示在一个连续的范围内
例11:查询编号为3至8的学生
```sql
select * from students where id between 3 and 8;
```
例12:查询编号是3至8的男生
```sql
select * from students where (id between 3 and 8) and gender=1;
```
空判断
-
注意:null与''是不同的
-
判空is null
例13:查询没有填写身高的学生
```sql
select * from students where height is null;
```
- 判非空is not null
例14:查询填写了身高的学生
```sql
select * from students where height is not null;
```
例15:查询填写了身高的男生
```sql
select * from students where height is not null and gender=1;
```
优先级
-
优先级由高到低的顺序为:小括号,not,比较运算符,逻辑运算符
-
and比or先运算,如果同时出现并希望先算or,需要结合()使用
2. 排序
为了方便查看数据,可以对数据进行排序
语法:
```sql
select * from 表名 order by 列1 asc|desc ,列2 asc\|desc,...
```
说明
-
将行数据按照列1进行排序,如果某些行列1的值相同时,则按照列2排序,以此类推
-
默认按照列值从小到大排列(asc)
-
asc从小到大排列,即升序
-
desc从大到小排序,即降序
例1:查询未删除男生信息,按学号降序
```sql
select * from students where gender=1 and is_delete=0 order by id desc;
```
例2:显示所有的学生信息,先按照年龄从大-->小排序,当年龄相同时 按照身高从高-->矮排序
```sql
select * from students order by age desc,height desc;
```
3. 聚合函数
为了快速得到统计数据,经常会用到如下5个聚合函数
总数
- count(*)表示计算总行数,括号中写星与列名,结果是相同的
例1:查询学生总数
```sql
select count(*) from students;
```
最大值
- max(列)表示求此列的最大值
例2:查询女生的编号最大值
```sql
select max(id) from students where gender=2;
```
最小值
- min(列)表示求此列的最小值
例3:查询未删除的学生最小编号
```sql
select min(id) from students where is_delete=0;
```
求和
- sum(列)表示求此列的和
例4:查询男生的总年龄
```sql
select sum(age) from students where gender=1;
-- 平均年龄
select sum(age)/count(*) from students where gender=1;
```
平均值
- avg(列)表示求此列的平均值
例5:查询未删除女生的编号平均值
```sql
select avg(id) from students where is_delete=0 and gender=2;
```
4. 分组
group by
-
group by的含义:将查询结果按照1个或多个字段进行分组,字段值相同的为一组
-
group by可用于单个字段分组,也可用于多个字段分组
```
gender count members
1 20 小红,小花,小紫....
0 30 大明,二明
```
group by + group_concat()
-
group_concat(字段名)可以作为一个输出字段来使用,
-
表示分组之后,根据分组结果,使用group_concat()来放置每一组的某字段的值的集合
```sql
select gender from students group by gender;
+--------+
| gender |
+--------+
| 男 |
| 女 |
| 中性 |
| 保密 |
+--------+
select gender,group_concat(name) from students group by gender;
+--------+-----------------------------------------------------------+
| gender | group_concat(name) |
+--------+-----------------------------------------------------------+
| 男 | 彭于晏,刘德华,周杰伦,程坤,郭靖 |
| 女 | 小明,小月月,黄蓉,王祖贤,刘亦菲,静香,周杰 |
| 中性 | 金星 |
| 保密 | 凤姐 |
+--------+-----------------------------------------------------------+
select gender,group_concat(id) from students group by gender;
+--------+------------------+
| gender | group_concat(id) |
+--------+------------------+
| 男 | 3,4,8,9,14 |
| 女 | 1,2,5,7,10,12,13 |
| 中性 | 11 |
| 保密 | 6 |
+--------+------------------+
```
group by + 集合函数
- 通过group_concat()的启发,我们既然可以统计出每个分组的某字段的值的集合,那么我们也可以通过集合函数来对这个`值的集合`做一些操作
```sql
select gender,group_concat(age) from students group by gender;
+--------+----------------------+
| gender | group_concat(age) |
+--------+----------------------+
| 男 | 29,59,36,27,12 |
| 女 | 18,18,38,18,25,12,34 |
| 中性 | 33 |
| 保密 | 28 |
+--------+----------------------+
分别统计性别为男/女的人年龄平均值
select gender,avg(age) from students group by gender;
+--------+----------+
| gender | avg(age) |
+--------+----------+
| 男 | 32.6000 |
| 女 | 23.2857 |
| 中性 | 33.0000 |
| 保密 | 28.0000 |
+--------+----------+
分别统计性别为男/女的人的个数
select gender,count(*) from students group by gender;
+--------+----------+
| gender | count(*) |
+--------+----------+
| 男 | 5 |
| 女 | 7 |
| 中性 | 1 |
| 保密 | 1 |
+--------+----------+
gender avg_age
1 20
0 18
```
group by + having
-
having 条件表达式:用来分组查询后指定一些条件来输出查询结果
-
having作用和where一样,但having只能用于group by
```sql
select gender,count(*) from students group by gender having count(*)>2;
+--------+----------+
| gender | count(*) |
+--------+----------+
| 男 | 5 |
| 女 | 7 |
+--------+----------+
```
5. 获取部分行
当数据量过大时,在一页中查看数据是一件非常麻烦的事情
语法
```sql
select * from 表名 limit start,count
```
说明
- 从start开始,获取count条数据
例1:查询前3行男生信息
```sql
select * from students where gender=1 limit 0,3;
```
示例:分页
-
已知:每页显示m条数据,当前显示第n页
-
求总页数:此段逻辑后面会在python中实现
-
查询总条数p1
-
使用p1除以m得到p2
-
如果整除则p2为总数页
-
如果不整除则p2+1为总页数
-
求第n页的数据
```sql
select * from students where is_delete=0 limit (n-1)*m,m
```
6. 连接查询
当查询结果的列来源于多张表时,需要将多张表连接成一个大的数据集,再选择合适的列返回
mysql支持三种类型的连接查询,分别为:
-
内连接查询:查询的结果为两个表匹配到的数据
-
右连接查询:查询的结果为两个表匹配到的数据,右表特有的数据,对于左表中不存在的数据使用null填充
-
左连接查询:查询的结果为两个表匹配到的数据,左表特有的数据,对于右表中不存在的数据使用null填充
```
需求:查询数据库获取小红的工资和部门信息。
select * from employees where id = 1;
select employees.id,employees.name,employees.salary,department.dept_name from employees
join department
on department.id = employees.department_id
where employees.id = 1;
select employees.id,employees.name,employees.salary,department.dept_name from employees
right join department
on department.id = employees.department_id
where employees.id = 1;
select employees.id,employees.name,employees.salary,department.dept_name from employees
left join department
on department.id = employees.department_id
where employees.id = 1;
select employees.id,employees.name,employees.salary,department.dept_name from employees join department
on department.id = employees.department_id
where employees.id = 3;
```
语法
```sql
select * from 表1 inner或left或right join 表2 on 表1.列 = 表2.列
```
例1:使用内连接查询班级表与学生表
```sql
select * from students inner join classes on students.cls_id = classes.id;
```
例2:使用左连接查询班级表与学生表
- 此处使用了as为表起别名,目的是编写简单
```sql
select * from students as s left join classes as c on s.cls_id = c.id;
```
例3:使用右连接查询班级表与学生表
```sql
select * from students as s right join classes as c on s.cls_id = c.id;
```
例4:查询学生姓名及班级名称
```sql
select s.name,c.name from students as s inner join classes as c on s.cls_id = c.id;
```
七、Python操作MySQL
1. 安装 pymysql
```bash
pip install pymysql
```
2. 连接数据库
```python
import pymysql
连接数据库
conn = pymysql.connect(
host='localhost', # 主机名
user='your_username', # 用户名
password='your_password', # 密码
database='your_database', # 数据库名
charset='utf8mb4', # 字符集
cursorclass=pymysql.cursors.DictCursor # 返回字典格式的结果
)
try:
创建游标对象
with conn.cursor() as cursor:
执行 SQL 查询
sql = "SELECT VERSION()"
cursor.execute(sql)
获取单条数据
result = cursor.fetchone()
print(f"数据库版本: {result}")
finally:
关闭数据库连接
conn.close()
```
3. 创建表
```python
try:
with conn.cursor() as cursor:
创建 users 表
sql = """
CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT,
email VARCHAR(100) UNIQUE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
"""
cursor.execute(sql)
提交事务
conn.commit()
print("表创建成功")
except Exception as e:
print(f"表创建失败: {e}")
回滚事务
conn.rollback()
```
4. 插入数据
```python
try:
with conn.cursor() as cursor:
插入单条数据
sql = "INSERT INTO users (name, age, email) VALUES (%s, %s, %s)"
cursor.execute(sql, ('Alice', 25, 'alice@example.com'))
插入多条数据
users = [
('Bob', 30, 'bob@example.com'),
('Charlie', 22, 'charlie@example.com')
]
sql = "INSERT INTO users (name, age, email) VALUES (%s, %s, %s)"
cursor.executemany(sql, users)
提交事务
conn.commit()
print(f"成功插入 {cursor.rowcount} 条数据")
except Exception as e:
print(f"数据插入失败: {e}")
conn.rollback()
```
5. 查询数据
```python
查询所有数据
try:
with conn.cursor() as cursor:
sql = "SELECT * FROM users"
cursor.execute(sql)
results = cursor.fetchall() # 获取所有记录
for row in results:
print(f"ID: {row'id'}, 姓名: {row'name'}, 年龄: {row'age'}, 邮箱: {row'email'}")
except Exception as e:
print(f"查询失败: {e}")
查询单条数据
try:
with conn.cursor() as cursor:
sql = "SELECT * FROM users WHERE id = %s"
cursor.execute(sql, (1,))
result = cursor.fetchone() # 获取单条记录
print(f"ID为1的用户: {result}")
except Exception as e:
print(f"查询失败: {e}")
```
6. 更新数据
```python
try:
with conn.cursor() as cursor:
sql = "UPDATE users SET age = age + 1 WHERE name = %s"
cursor.execute(sql, ('Alice',))
提交事务
conn.commit()
print(f"成功更新 {cursor.rowcount} 条数据")
except Exception as e:
print(f"数据更新失败: {e}")
conn.rollback()
```
7. 删除数据
```python
try:
with conn.cursor() as cursor:
sql = "DELETE FROM users WHERE age < %s"
cursor.execute(sql, (25,))
提交事务
conn.commit()
print(f"成功删除 {cursor.rowcount} 条数据")
except Exception as e:
print(f"数据删除失败: {e}")
conn.rollback()
```
8. 使用上下文管理器管理连接
为了简化资源管理,可以将数据库连接封装成上下文管理器:
```python
class MySQLConnection:
def init(self, host, user, password, database):
self.host = host
self.user = user
self.password = password
self.database = database
self.conn = None
def enter(self):
self.conn = pymysql.connect(
host=self.host,
user=self.user,
password=self.password,
database=self.database,
cursorclass=pymysql.cursors.DictCursor
)
return self.conn
def exit(self, exc_type, exc_val, exc_tb):
if self.conn:
self.conn.close()
使用示例
with MySQLConnection('localhost', 'user', 'password', 'dbname') as conn:
with conn.cursor() as cursor:
cursor.execute("SELECT * FROM users")
results = cursor.fetchall()
for row in results:
print(row)
```
9. 处理数据库事务
```python
try:
with conn.cursor() as cursor:
开始事务
conn.begin()
执行多个操作
cursor.execute("INSERT INTO users (name, age) VALUES (%s, %s)", ('David', 28))
cursor.execute("UPDATE users SET age = age + 1 WHERE name = 'Bob'")
提交事务
conn.commit()
print("事务提交成功")
except Exception as e:
回滚事务
conn.rollback()
print(f"事务回滚: {e}")
```
```
create table blog(
id int unsigned not null auto_increment comment "主键",
title varchar(200) not null comment "文章标题",
authoer varchar(50) not null comment "文章作者",
description varchar(500) not null comment "文章摘要",
content text not null comment "内容",
primary key(id)
)charset=utf8;
```