MySQL主键和外键使用及说明
摘自网上一个经典的例子:大哥和小弟
一、外键约束
MySQL通过外键约束来保证表与表之间的数据的完整性和准确性。
外键的使用条件:
1.两个表必须是InnoDB表,MyISAM表暂时不支持外键(据说以后的版本有可能支持,但至少目前不支持);
2.外键列必须建立了索引,MySQL 4.1.2以后的版本在建立外键时会自动创建索引,但如果在较早的版本则需要显示建立;
3.外键关系的两个表的列必须是数据类型相似,也就是可以相互转换类型的列,比如int和tinyint可以,而int和char则不可以;
外键的好处:可以使得两张表关联,保证数据的一致性和实现一些级联操作;
外键的定义语法:
[constraint symbol] foreign key [id] (index_col_name, ...)
references tbl_name (index_col_name, ...)
[on delete {restrict | cascade | set null | on action | set default}]
[on update {restrict | cascade | set null | on action | set default}] 该语法可以在 create table 和 alter table 时使用,如果不指定constraint symbol,MYSQL会自动生成一个名字。
on delete,on update表示事件触发限制,可设参数:
restrict(限制外表中的外键改动)
cascade(跟随外键改动)
set null(设空值)
set default(设默认值)
no action(无动作,默认的)
1. 先建立1个新的数据库
2.在pycharm中新建2张table(Dage,Xiaodi)
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String,ForeignKey engine=create_engine("mysql+pymysql://root:1234@localhost/chen")
Base=declarative_base()
class Dage(Base):
__tablename__='Dage'
id=Column(Integer,primary_key=True)
name=Column(String(32))
class Xiaodi(Base):
__tablename__='Xiaodi'
id=Column(Integer,primary_key=True)
name=Column(String(32))
Dage_id = Column(Integer,ForeignKey('Dage.id'))
Base.metadata.create_all(engine)
在客户端show table已经创建过程
show create table xiaodi;
----------------------------------------------------------------------+
| xiaodi | CREATE TABLE `xiaodi` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) DEFAULT NULL,
`Dage_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `Dage_id` (`Dage_id`),
CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`Dage_id`) REFERENCES `dage` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
show create table dage;
3.在2张表中各插入1条数据。由于不知名的错误,需要把2个表中的数据分开创建。
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String,ForeignKey
from sqlalchemy.orm import sessionmaker engine=create_engine("mysql+pymysql://root:1234@localhost/chen")
Base=declarative_base()
class Dage(Base):
__tablename__='Dage'
id=Column(Integer,primary_key=True)
name=Column(String(32))
class Xiaodi(Base):
__tablename__='Xiaodi'
id=Column(Integer,primary_key=True)
name=Column(String(32))
Dage_id = Column(Integer,ForeignKey('Dage.id'))
Base.metadata.create_all(engine) Session_class=sessionmaker(bind=engine)
session=Session_class()
#dage1=Dage(name='I_am_dage')
xiaodi1=Xiaodi(Dage_id=1,name='I_am_xiaodi')
session.add_all([xiaodi1])
session.commit()
查看效果:发现这种创建方式有个问题,id会自增,2张表的ID依次为1,2
4.尝试删除大哥
删除不了,因为有外键约束
插入1个小弟,因为没有大哥,所以插入不成功
5.把外键约束增加事件触发限制:
alter table xiaodi drop foreign key xiaodi_ibfk_1;
alter table xiaodi add foreign key(Dage_id) references dage(id) on delete cascade on update cascade; #意思是从表会跟随主表的改变而改变。
理论上,现在就能正常删除了。
二,多外键关联
建立一个customer表和一个地址表
表结构:
from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine Base = declarative_base() class Customer(Base):
__tablename__ = 'customer'
id = Column(Integer, primary_key=True)
name = Column(String(64))
# 账单地址和邮寄地址 都关联同一个地址表
billing_address_id = Column(Integer, ForeignKey("address.id"))
shipping_address_id = Column(Integer, ForeignKey("address.id")) billing_address = relationship("Address", foreign_keys=[billing_address_id])
shipping_address = relationship("Address", foreign_keys=[shipping_address_id]) class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
city = Column(String(64))
def __repr__(self):
return self.street engine = create_engine("mysql+pymysql://root:1234@localhost/chen",
encoding='utf-8')
Base.metadata.create_all(engine) # 创建表结构
生成表内容:
from Day12 import ex5 from sqlalchemy.orm import sessionmaker Session_class = sessionmaker(bind=ex5.engine) # 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例 session = Session_class() # 生成session实例 #cursor addr1 = ex5.Address(city="BJ") addr2 = ex5.Address(city="Shanghai") addr3 = ex5.Address(city="Tianjin") session.add_all([addr1, addr2, addr3]) c1 = ex5.Customer(name="Alex", billing_address=addr1, shipping_address=addr2) c2 = ex5.Customer(name="Jack", billing_address=addr3, shipping_address=addr3) session.add_all([c1, c2]) session.commit()
效果:
查询:
obj=session.query(ex5.Customer).filter(ex5.Customer.name=='Alex').first()
print(obj.name,obj.billing_address,obj.shipping_address)
返回结果:
C:\abccdxddd\Oldboy\python-3.5.2-embed-amd64\python.exe C:/abccdxddd/Oldboy/Py_Exercise/Day12/ex4.py
Alex BJ Shanghai Process finished with exit code 0
三,多对多
1.创建表结构
import sqlalchemy
from sqlalchemy import Table, Column, Integer,String,DATE, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker Base=declarative_base()
book_m2m_author=Table('book_m2m_author',Base.metadata,
Column('book_id',Integer,ForeignKey('books.id')),
Column('author_id',Integer,ForeignKey('authors.id')),
) class Book(Base):
__tablename__='books'
id=Column(Integer,primary_key=True)
name=Column(String(64))
authors=relationship('Author',secondary=book_m2m_author,backref='books')
def __repr__(self):
return self.name class Author(Base):
__tablename__='authors'
id=Column(Integer,primary_key=True)
name=Column(String(32))
def __repr__(self):
return self.name
engine=create_engine('mysql+pymysql://root:1234@localhost/chen')
Base.metadata.create_all(engine)
2. 增加表内容
# 添加数据 from Day12 import ex4
from sqlalchemy.orm import sessionmaker
Session_class = sessionmaker(bind=ex4.engine) # 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例 session = Session_class() # 生成session实例 #cursor # 创建书 b1 = ex4.Book(name="learn python with Alex")
b2 = ex4.Book(name="learn Zhangbility with Alex")
b3 = ex4.Book(name="Learn hook up girls with Alex") # 创建作者 a1 = ex4.Author(name="Alex")
a2 = ex4.Author(name="Jack")
a3 = ex4.Author(name="Rain") # 关联关系 b1.authors = [a1, a3]
b3.authors = [a1, a2, a3] session.add_all([b1, b2, b3, a1, a2, a3])
session.commit()
查看效果:
3. 通过作者查询书
4.通过书查作者
MySQL主键和外键使用及说明的更多相关文章
- MySQL的几个概念:主键,外键,索引,唯一索引
概念: 主键(primary key) 能够唯一标识表中某一行的属性或属性组.一个表只能有一个主键,但可以有多个候选索引.主键常常与外键构成参照完整性约束,防止出现数据不一致.主键可以保证记录的唯一和 ...
- mysql主键,外键,索引
主键 唯一而非空,只能有一个 作用: 1.唯一的标识一行 2.作为一个可以被外键有效引用的对象 3.保证数据完整性 设计原则: 1. 主键应当是对用户没有意义的.如果用户看到了一个表示多对多关系的 ...
- MySQL—概念,用户的创建,主键,外键,数据类型,表格创建
MySQL DBMS,MySQL的概念,数据库分类,以前MySQL的部署中的一些概念 #DBMS:数据库管理系统,用于管理数据库的大型软件.mysql就是dbms的一种 #Mysql:是用于管理文件的 ...
- MySQL中的主键,外键有什么作用详解
MySQL中的主键,外键有什么作用详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 学关系型数据库的同学,尤其在学习主键和外键时会产生一定的困惑.那么今天我们就把这个困惑连根拔起 ...
- 两种获取MySql数据库中所有表的主键和外键约束信息的Sql语句
最近在写Rafy底层的一些东西,在数据库方面把MySql数据库集成到里面去,里面有一个需求,需要获取非系统数据库,也就是我们自己建立的数据库中所有表的主键和外键元数据列表. 第一种方法:是网上的方法, ...
- MySql必知必会实战练习(四)主键、外键、sql约束、联结表
本博将对主键.外键.MySql数据库约束和联结表的相关特性进行总结和实战 1. 主键 表中的每一行都应该具有可以唯一标识自己的一列(或一组列),而这个承担标识作用的列称为主键 如果没有主键,数据的管理 ...
- mysql的引擎问题,主键和外键的创建问题,以及创建外键不成功,却创建了一个索引
mysql的引擎问题: 需要知道的三个引擎:InnoDB--是一个事务处理引擎,不支持全文检索,支持事务操作,即DML操作: Memory--是一个数据存储在内存,速度很快,功能上等同于MyIsam, ...
- day03 MySQL数据库之主键与外键
day03 MySQL数据库之主键与外键 昨日内容回顾 针对库的基本SQL语句 # 增 create database meng; # 查 show databases; shwo create da ...
- MySQL中的完整性约束条件(主键、外键、唯一、非空)
数据库的完整性约束用来防止对数据的意外破坏,来保证数据的安全性和一致性. 主键 1.创建表时候指定主键 创建表user(id, username, age),并且id字段非空自增. CREATE TA ...
- MySQL主键跟外键
定义主键和外键主要是为了维护关系数据库的完整性,总结一下: 1.主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年龄. 身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证 ...
随机推荐
- day1 函数 (独立功能代码块)
1.引入函数 2.函数执行过程 4.带参数的函数 5.带返回值的函数 6. 多个返回值 (return a,b,c)元组 7.4种函数 1.引入函数 独立功能代码块 ---> 封装 ----&g ...
- 【JUC源码解析】LinkedBlockingQueue
简介 一个基于链表的阻塞队列,FIFO的顺序,head指向的元素等待时间最长,tail指向的元素等待时间最短,新元素从队列尾部添加,检索元素从队列头部开始,队列的容量,默认是Integer#MAX_V ...
- Maven学习(九)-----定制库到Maven本地资源库
这里有2个案例,需要手动发出Maven命令包括一个 jar 到 Maven 的本地资源库. 要使用的 jar 不存在于 Maven 的中心储存库中. 您创建了一个自定义的 jar ,而另一个 Mave ...
- Linux系统中Oracle11g数据库的安装与验证
1.查看Linux系统的位数 2.下载Oracle10g数据库软件 https://blog.csdn.net/xiezuoyong/article/details/81197688 (需要注册Ora ...
- 05-Docker架构详解
Docker 的核心组件包括: Docker 客户端 - Client Docker 服务器 - Docker daemon Docker 镜像 - Image Registry Docker 容器 ...
- Openwrt之移动硬盘ext3/ext4格式化工具
在给openwrt挂载移动硬盘的时候,最好是ext3/ext4方式,但在windows下苦于无法找到合适的工具进行格式化. 踅摸了半天,终于找到了它:MiniTool Partion Wizard ...
- arcgis10.2怎么把地理坐标系转化为投影坐标系(平面,米制坐标) arcmap 10.2 从 WGS_1984 转 Beijing_1954
方法一:在Arcmap中转换:从 WGS_1984 转 Beijing_19541.加载要转换的数据,右下角为经纬度2.点击视图——数据框属性——坐标系统3.导入或选择正确的坐标系(如选:Beijin ...
- Python3 函数式编程自带函数
一 map函数 引子 需求1:num1=[1,2,3,4],我的需求是把num1中的每个元素平方后组成新列表. ret = [] num1 = [1,2,3,4] for i in num1: ret ...
- 2018软工实践—Alpha冲刺(9)
队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 多次测试软件运行 学习OPENMP ...
- Spring的事务到底该给Dao配置还是给Service配置
Spring的事务到底该给Dao配置还是给Service配置 Spring事务为业务逻辑进行事务管理,保证业务逻辑上数据的原子性. 事务得根据项目性质来细分:事务可以设置到三个层面(dao层.serv ...