Connect SQL with python

- 4 mins

Để connect sql với python có một số cách sau:

Giả sử ta có query sau:

SELECT
 c.country
 ,c.year
 ,MAX(e.horse_power) AS max_horse_power
FROM public.cars c
JOIN public.engines e
 ON c.engine_name = e.name
WHERE c.country != 'USA'
GROUP BY
 c.country
 ,c.year
HAVING MAX(e.horse_power) > 200
ORDER BY max_horse_power DESC

Bỏ qua các trường, mục đích của câu query, trong query này, có nhiều các toán tử hay được sử dụng. Để query câu lệnh này đến database ta có thể dùng một số cách sau:

Raw SQL

Cách phổ biến nhất khi mới bắt đầu giao tiếp với sql qua python là viết câu lệnh sql sau đó giao tiếp với sql thông qua thư viện hỗ trợ client sql thuần như pymysql.

import pymysql.cursors

# Connect to the database
connection = pymysql.connect(host='localhost',
                             user='user',
                             password='passwd',
                             database='db',
                             cursorclass=pymysql.cursors.DictCursor)

with connection:
    with connection.cursor() as cursor:
        # Create a new record
        sql = "INSERT INTO `users` (`email`, `password`) VALUES (%s, %s)"
        cursor.execute(sql, ('webmaster@python.org', 'very-secret'))

    # connection is not autocommit by default. So you must commit to save
    # your changes.
    connection.commit()

    with connection.cursor() as cursor:
        # Read a single record
        sql = "SELECT `id`, `password` FROM `users` WHERE `email`=%s"
        cursor.execute(sql, ('webmaster@python.org',))
        result = cursor.fetchone()
        print(result)

ORM

ORM (Object relational mapping) là một kĩ thuật giao tiếp với các database thông qua các class và object được tạo trong code mapping với các table trong database. Đây là cách phổ biến được dùng trong nhiều ứng dụng hiện nay. Trong python, thư viện phổ biến hỗ trợ ORM được sử dụng là SQLAlchemy. Ngoài ra trong một số framework như Django, FastAPI cũng hỗ trợ ORM

from dotenv import load_dotenv
import os

from sqlalchemy import URL, create_engine, func, select
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column
from sqlalchemy.types import Integer, String

class Base(DeclarativeBase):
    pass

class Cars(Base):
    __tablename__ = "cars"
    
    manufacturer: Mapped[str] = mapped_column(String(64))
    model: Mapped[str] = mapped_column(String(64))
    country: Mapped[str] = mapped_column(String(64))
    engine_name: Mapped[str] = mapped_column(String(64), primary_key=True, nullable=False)
    year: Mapped[int] = mapped_column(Integer)
    
class Engines(Base):
    __tablename__ = "engines"
    
    name: Mapped[str] = mapped_column(String(64), primary_key=True, nullable=False)
    horse_power: Mapped[int] = mapped_column(Integer)


def main():
    
    load_dotenv()
    
    connection_string = URL.create(
        'postgresql',
        username=os.getenv('USERNAME'),
        password=os.getenv('PASSWORD'),
        host=os.getenv('HOST'),
        database=os.getenv('DB'),
        #connect_args={'sslmode':'require'}
        )
    
    engine = create_engine(connection_string)
    session = Session(engine)
    
    sql = (
        select(
            Cars.country,
            Cars.year,
            func.max(Engines.horse_power).label("max_horse_power"),
        )
        .join(Engines, Cars.engine_name == Engines.name)
        .where(Cars.country != 'USA')
        .group_by(Cars.country, Cars.year)
        .having(func.max(Engines.horse_power) > 200)
        .order_by(func.max(Engines.horse_power).label("max_horse_power").desc())
    )
    
    for i in session.execute(sql):
        print(i)


if __name__ == '__main__':
    main()

#('Germany', 2019, 612)
#('UK', 2019, 612)
#('Germany', 2021, 510)
#('Germany', 2023, 469)

Ở ví dụ trên, thay vì viết tên các table, database trong câu query thì tạo các class tương ứng với các table này (class Cars, Engines)

SQL query builder

Ngoài cách viết query thuần và sử dụng thư viện hỗ trợ ORM, còn có thể dùng thư viện hỗ trợ build câu query kết hợp (sử dụng builder pattern) với thư viện như pymysql để truy vấn kết quả

Thư viện hỗ trợ builder câu query có thể sử dụng như pypika.

from pypika import Table, Query

customers = Table('customers')
q = Query.from_(customers).select(customers.id, customers.fname, customers.lname, customers.phone)
comments powered by Disqus
rss facebook twitter github gitlab youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora