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.通過書查作者

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM