Featured image of post SQLAlchemy - 你的Database互動好幫手

SQLAlchemy - 你的Database互動好幫手

SQLAlchemy 入門篇

簡介

在資料科學的入門階段,使用SQLAlchemy建立與資料庫的連線,並透過Pandas進行資料的讀取以及寫入是非常基礎的做法。然而SQLAlchemy所提供的功能可不只是建立連線那麼陽春。我們將會在SQLAlchemy的系列文章中,為大家介紹SQLAlchemy所提供的各種好用功能。在本文中,我們將會為讀者介紹:

  1. 使用SQLAlchemy建立與資料庫的連線
  2. 使用Cursor進行資料庫操作
  3. 透過SQLAlchemy建構資料表
  4. 透過SQLAlchemy建構資料表之間的關聯性
  5. 透過SQLAlchemy進行資料的新增、更新以及刪除

使用SQLAlchemy建立與資料庫的連線

使用SQLAlchemy建立對各個資料庫的連線,是最基礎也最重要的功能。在使用上,需要使用create_engine這個功能,搭配宣告資料庫以及對應的連線工具等資訊來進行連線的建立。以下簡單示範如何建立與SQLite以及PostgreSQL資料庫的連線。

SQLite

在這邊我們簡單示範如何建立與使用記憶體空間建立的SQLite資料庫之間的連線:

1
2
from sqlalchemy import create_engine
engine = create_engine("sqlite://", echo=True)

PostgreSQL

要使用SQlalchemy建立與PostgreSQL之間的連線,需要先安裝額外的工具psycopg2或是asyncpg。(後者支援async的操作)

1
pip install psycopg2 asyncpg

接下來,我們需要準備一個database_url來宣告以下資訊:

  • 資料庫類型
  • 資料庫連線工具
  • 資料庫IP以過Port
  • 使用者名稱以及密碼
  • 資料庫Schema
1
2
3
4
5
# psycopg2
database_url = "postgresql+psycopg2://<使用者名稱>:<密碼>@<資料庫IP>:<資料庫Port>/<資料庫Schema>"

# asyncpg
database_url = "postgresql+asyncpg://<使用者名稱>:<密碼>@<資料庫IP>:<資料庫Port>/<資料庫Schema>"

接下來,我們可以使用create_engine或是create_async_engine來建立連線:

1
2
3
4
5
# create_engine
engine = create_engine(database_url, echo=True)

# create_async_engine
engine = create_async_engine(database_url, echo=True)

使用Cursor進行資料庫操作

在SQLAlchemy所提供的功能中,可以使用cursor來直接與資料庫進行互動。使用cursor進行互動可以說是最直接,但也最浪費SQLAlchemy所提供的各種好用功能的做法。接下來我將示範如何建立cursor並與資料庫進行互動。cursor物件可以透過engine.conntect()所產生的物件來獲得:

1
2
connect = engine.connect()
cursor = connect.cursor()

接下來,我們可以使用cursor.execute搭配SQL語法來進行互動。

1
2
3
4
5
6
7
8
9
statement = """
CREATE TABLE cars (
  brand VARCHAR(255),
  model VARCHAR(255),
  year INT
);
"""

cursor.execute(statement)

通過以上的操作,我們可以使用cursor建立一個具有brandyear以及model三個欄位的cars資料表。

透過SQLAlchemy建構資料表

在上一個章節中,我們提到直接使用cursor來與資料庫進行互動是非常不推薦的做法。接下來我們將介紹如何使用SQLAlchemy所提供的功能來建立資料表以及其內部的欄位。SQLAlchemy提供基於對象關係對映(Object Relational Mapping, ORM)來進行資料互動的方法。實作上,我們可以使用DeclarativeBaseColumn來建立資料表:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from sqlalchemy import Column, String, Integer
from sqlalchemy.orm import DeclarativeBase

class Base(DeclarativeBase):
    pass

class Car(Base):
    __tablename__ = "cars"

    id = Column("id", Integer, primary_key=True)
    brand = Column("brand", String)
    model = Column("model", String)
    year = Column("year", Integer)

在上面的程式碼中,我們首先建立了一個基於DeclarativeBaseBase物件,並使用此物件來建構後續的資料表。接下來,我們繼承Base類別的基礎之上,建立了一個Car類別。這個Car類別將是一個資料表。

在建立了Car類別後,我們在類別內部定義了四個欄位:

  • id:用以作為primary key的欄位。
  • brand:用以記錄產品資訊的欄位。
  • model:用以記錄型號的欄位。
  • year:用以記錄產品年份。

並且,我們使用__tablename__來定義了資料表在資料庫之中的名稱。在完成了資料表以及欄位的創建之後,我們可以使用Base物件的create_all搭配engine來建立我們所定義的資料表以及相對應的欄位:

1
Base.metadata.create_all(engine)

這樣就可以建立一個名為cars的資料表。

透過SQLAlchemy建構資料表之間的關聯性

接下來,我們可以新增另一張表,並在兩張表之間建立關聯性。接下來我們將建立一張customer資料表,並記錄每一個使用者的姓名,以及其購買的車輛型號。customer資料表中的車輛型號,將會以cars資料表的model欄位作為Foreign key。

1
2
3
4
5
6
7
8
9
from sqlalchemy import ForeignKey

class Customer(Base):
    __tablename__ = "customer"

    id = Column("id", Integer, primary_key=True)
    first_name = Column("first_name", String)
    last_name = Column("last_name", String)
    car_model = Column("car_model", String, ForeignKey("cars.model"))

同樣的,我們可以使用Basecreate_all來進行資料表的建立:

1
Base.metadata.create_all(engine)

透過SQLAlchemy進行資料的新增、更新以及刪除

SQLAlchemy提供了selectupdate、以及delete來進行對記錄的選取、更新以及刪除的功能。接下來我們將會分別示範這三個功能。

新增一筆資料

為了後續的示範,我們可以先為我們的資料表新增一筆資料。我們可以使用sqlalchemy.orm所提供的Session來進行資料的新增等操作:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from sqlalchemy.orm import Session

with Session(engine) as session:
    car = Car(
        id=1,
        brand="test",
        model="test",
        year=2021
    )

    session.add(car)
    session.commit()

在上方,我們透過Session以及engine建立一個session,並使用session將我們建立的car資料新增至資料庫。

SELECT

在上一個章節,我們為資料表新增了一筆資料。假設我們想要從cars資料表中取出所有資料,我們可以使用select來進行操作:

1
2
3
4
5
6
from sqlalchemy import select

with Session(engine) as session:
    stmt = select(Car)

    result = session.execute(stmt)

或許讀者會注意到我們使用list將運算的結果轉換為列表物件。為何會需要使用list()來進行轉換呢?這是因為session.execute所回傳的物件為一個生成器物件,我們需要使用list或是其他方法來將生成器物件轉為可以疊代的物件。

此外,select也提供使用where方法來進行資料的篩選。假設我們想要取出產品年份為2021年的資料,我們可以:

1
2
3
4
5
6
from sqlalchemy import select

with Session(engine) as session:
    stmt = select(Car).where(Car.year = 2021)

    result = session.execute(stmt)

UPDATE

SQLAlchemy除了select以外,也提供了update功能來讓使用者可以進行資料的更新。以下我們將示範如何將先前的資料,透過update來進行更新。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from sqlalchemy import update

with Session(engine) as session:
    stmt = (
        update(Car)
        .where(Car.year == 2021)
        .values(brand="test1")
    )

    session.execute(stmt)
    session.commit()

在上方的程式碼中,我們使用update(Car)來指定要對cars資料表進行操作;接下來我們使用了where來指定了需要被更新的欄位。在篩選了要修改的資料之後,我們可以使用values來進行資料的更新。

DELETE

最後,我們將介紹如何使用delete來進行資料的刪除。要刪除一筆資料,只需要透過將要處理的資料表作為參數傳遞給delete,並使用where來限定需要被刪除的資料即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from sqlalchemy import delete

with Session(engine) as session:
    stmt = (
        delete(Car)
        .where(Car.year == 2021)
    )

    session.execute(stmt)
    session.commit()

小節

在這篇文章中,我們介紹了如何透過SQLAlchemy所提供的功能,在基於ORM的概念之上,進行資料表以及欄位的建立和操作。透過這些功能,我們可以避免使用cursor以及直接撰寫SQL語法來進行資料的操作,也可以一定程度上的避免SQL Injection。在後續的文章中,我們將會繼續介紹其他SQLAlchemy所提供的好用功能。

comments powered by Disqus
使用 Hugo 建立
主題 StackJimmy 設計