SQL主键与外键

一、单表的约束

1.代表记录的唯一标识

2.声明某一列作为主键

·使用关键字primary key

3.主键的特点

·唯一

·非空

·被引用

4.创建一张表,声明主键

(1)第一种

(勾掉自动递增只加了主键,如果新增2个id为19的,就不行了,如果我不给值也不行

数据量庞大我们是记不住哪个是哪个的,我们打上自动递增,再新增就会默认往下加。自动递增保证数据唯一,但是不保证填充空位。)

create table person(

id int primary key,

name varchar(30)

);

insert into person values (1,'聪聪');

insert into person values (2,'美美');

insert into person values (3,'小凤');

Int不指定长度默认值为11

(2)第二种

create table person(

id int,

name varchar(30),

primary key (id)

);

自增长:维护主键信息

auto_increment;

create table person(

id int primary key auto_increment,

name varchar(30)

);

insert into person values (null,'聪聪');

insert into person values (null,'美美');

insert into person values (null,'小凤');

删除id为1的数据

delete from person where id = 1;

唯一和非空的解释

1.唯一:字段唯一,使用关键字unique;

2.非空:不允许为null,使用not null;比如主键

二、多表外键的约束

create table dept(

did int primary key auto_increment,

dname varchar(30)

);

create table emp(

eid int primary key auto_increment,

ename varchar(30),

sal double, dno int

);

insert into dept values (1,'研发部');

insert into dept values (2,'人事部');

insert into emp values (null,'聪聪',15000,1);

insert into emp values (null,'邦邦',5000,1);

insert into emp values (null,'美美',6000,2);

insert into emp values (null,'小凤',8000,2);

insert into emp values (null,'如花',8000,null);

问题:

·直接删掉研发部。Delete from dept where did=1;可以删除

·在现实生活中并不合理,如果你避免问题的发生,两个表之间应该设置关系,删掉部门之前必须把部门下对应的成员删掉

可以看见dno为1的成员依然存在

1.引入外键约束

2.添加外键:

·正常情况下(一个部门有多个员工,一个员工只能属于一个部门)

·设置员工标签的dno字段,作为外键,指向部门表的主键。

·修改员工的表,在员工添加外键。

·alter table emp add foreign key emp (dno) references dept (did);

3.直接添加外键

·创建表的时候直接指定外键

create table emp(

eid int primary key auto_increment, ename varchar(30),

sal double, dno int,

foreign key emp(dno) references dept (did)

);

现在再直接删除部门就不可以了

三、表之间的关系(重要)

1.一对一(一张表解决)

一个人对应一个身份证号码,完全可以建立在一张表里边

2.多对一&一对多(可以用主外键约束)

·一对多:一个部门下有多个员工

·多对一:多个员工可以属于一个部门

练习:用户表&订单表

-- 1. 用户表(一的一方)

CREATE TABLE user (

id INT PRIMARY KEY AUTO_INCREMENT,

-- 主键 username VARCHAR(20) NOT NULL

);

-- 2. 订单表(多的一方,存外键 user_id)

CREATE TABLE `order` (

id INT PRIMARY KEY AUTO_INCREMENT,

order_no VARCHAR(30) NOT NULL,

-- 外键:关联 user 表的

id user_id INT, FOREIGN KEY (user_id) REFERENCES user(id) );

插入测试数据

INSERT INTO user(username) VALUES ('张三'),('李四');

INSERT INTO `order`(order_no, user_id) VALUES

('ORDER_001',1), -- 张三的订单

('ORDER_002',1), -- 张三的订单

('ORDER_003',2); -- 李四的订单

关联查询(重点)

-- 查询所有订单,同时显示对应用户名(多对一查询)

SELECT o.id, o.order_no, u.username FROM `order` o LEFT JOIN user u ON o.user_id = u.id;

-- 查询张三的所有订单(一对多查询)

SELECT o.* FROM `order` o JOIN user u ON o.user_id = u.id WHERE u.username = '张三';

3.多对多(需要产生中间表,这个表只维护关系)

学生和所选科目

一个学生可以选择多个科目

一个科目可以被多个学生选择

实操案例:

创建三张表:

-- 1. 学生表

CREATE TABLE student

( id INT PRIMARY KEY AUTO_INCREMENT,

name VARCHAR(20) NOT NULL

);

-- 2. 课程表

CREATE TABLE course (

id INT PRIMARY KEY AUTO_INCREMENT,

course_name VARCHAR(30) NOT NULL

);

-- 3. 中间表:学生选课表(核心!多对多必须有)

CREATE TABLE student_course (

student_id INT,

course_id INT,

);

-- 联合主键

PRIMARY KEY (student_id, course_id),

-- 两个外键

FOREIGN KEY (student_id) REFERENCES student(id),

FOREIGN KEY (course_id) REFERENCES course(id) );

插入数据:

-- 学生

INSERT INTO student(name) VALUES ('小明'),('小红');

-- 课程

INSERT INTO course(course_name) VALUES ('MySQL'),('Java'),('Python');

-- 选课关系(中间表)

INSERT INTO student_course(student_id, course_id) VALUES

(1,1), -- 小明选 MySQL

(1,2), -- 小明选 Java

(2,1), -- 小红选 MySQL

(2,3); -- 小红选 Python

四、多表关联查询(重点)

-- 查询每个学生选了哪些课

SELECT

s.name, c.course_name

FROM student s JOIN student_course sc

ON

s.id = sc.student_id JOIN course c

ON

sc.course_id = c.id;

-- 查询 MySQL 这门课被哪些学生选了

SELECT s.name

FROM

student s JOIN student_course sc ON s.id = sc.student_id JOIN course c ON sc.course_id = c.id WHERE c.course_name = 'MySQL';

Java中考虑拆成一对多,站在某一个表考虑

五、多表查询(重要)

先建表:

-- 用户表

CREATE TABLE user ( uid INT PRIMARY KEY, name VARCHAR(20) );

-- 订单表

CREATE TABLE orders ( oid INT PRIMARY KEY, uid INT, gid INT, money INT );

-- 商品表

CREATE TABLE goods ( gid INT PRIMARY KEY, gname VARCHAR(20) );

-- 插入数据

INSERT INTO user VALUES (1, '张三'), (2, '李四'), (3, '王五');

INSERT INTO goods VALUES (101, '手机'), (102, '电脑'), (103, '耳机');

INSERT INTO orders VALUES (1, 1, 101, 5000), (2, 1, 102, 8000), (3, 2, 101, 5000), (4, NULL, 103, 200); -- 没有用户的异常订单

1.笛卡尔积(一般要加约束的)

重复了,可以加入where条件再过滤 where dept.did=emp.dno;

2.内连接查询(inner join)

关键字inner join

不是where 是on了,但是效果差不多;

如果不写inner join就不能用on了,使用where, 像隐晦一点的内连接

--1. 用户表(左表)

CREATE TABLE `user` (

id INT PRIMARY KEY AUTO_INCREMENT,

username VARCHAR(20) NOT NULL );

-- 2. 订单表(右表)

CREATE TABLE `order` (

id INT PRIMARY KEY AUTO_INCREMENT,

order_no VARCHAR(30) NOT NULL,

user_id INT,

FOREIGN KEY (user_id) REFERENCES `user`(id)

);

3.-- 插入数据

INSERT INTO `user`(username) VALUES ('张三'),('李四'),('王五'),('赵六');

INSERT INTO `order`(order_no, user_id) VALUES ('ORDER_001',1), ('ORDER_002',1), ('ORDER_003',2);

LEFT JOIN:

SELECT 字段 FROM 左表 LEFT JOIN 右表 ON 左表.id = 右表.关联id;

RIGHT JOIN:

SELECT 字段 FROM 左表 RIGHT JOIN 右表 ON 左表.id = 右表.关联id;

SELECT u.id AS 用户id, u.username AS 用户名, o.order_no AS 订单号 FROM `user` u RIGHT JOIN `order` o ON u.id = o.user_id;

相关推荐
飞翔的馒1 小时前
浏览器缓存之【结构化数据库与缓存】: IndexedDB、Cache storage 和 Storage buckets
数据库·缓存
SelectDB1 小时前
SelectDB search():AI 日志搜索与分析场景的技术能力与实践
数据库
SelectDB1 小时前
Apache Doris 事务保障:技术能力、选型对比与企业实践
数据库
圣光SG1 小时前
Java操作题练习(二)
java·开发语言·python
SelectDB1 小时前
AI Observe Stack(基于 Apache Doris):AI Agent 可观测性技术能力、选型对比与实践
数据库
蜡台1 小时前
Android WebView 设计指南
android·java·kotlin
SelectDB1 小时前
PostgreSQL + Apache Doris HTAP 架构:技术能力、选型对比与企业实践
数据库
SelectDB1 小时前
SelectDB(飞轮科技)技术研发型企业认证:Apache Doris 核心能力、选型对比与实践
数据库