📚

SQLModelのクエリ一覧(SELECT編)

に公開

環境設定

バージョン情報

  • Python: 3.13.7
  • SQLModel: 0.0.31
  • DB: SQLite

uvでの環境設定

pyproject.toml
[project]
name = "SQLModelTest"
version = "1.0.0"
description = "SQLModelの動作等を確認する"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
    "sqlmodel>=0.0.31",
]

[dependency-groups]
dev = [
    "mypy>=1.17.1",
    "pytest>=8.4.1",
    "pytest-cov>=7.0.0",
    "pytest-mock>=3.14.1",
    "ruff>=0.12.10",
]

この記事で扱わないこと

  • Session, Engineの作成
  • トランザクション、排他制御

使用するモデル

以降のスクリプトは以下のモデルを使用する前提で記述しています。

article_modelpy
from uuid import UUID, uuid4
from sqlmodel import Field, Session, SQLModel, selec
from app.models import ArticleModel

class ArticleModel(SQLModel, table=True):
    """記事"""

    __tablename__ = "article"  # type: ignore[assignment]

    id: UUID = Field(primary_key=True, default_factory=uuid4, nullable=False)
    title: str = Field(nullable=False, description="タイトル")
    content: str = Field(nullable=False, description="本文")
    status: int = Field(nullable=False, description="記事公開状態(数値)")

SELECT文

IN

集合に含まれる値に一致するレコードを取得します。

in_querypy
from sqlmodel import Session, col, select
from app.models import ArticleModel

def in_query(session: Session) -> None:
    """status が 3 または 4 のレコードを取得する (IN)"""
    print("[in_query] status IN (3, 4)")
    sql = select(ArticleModel).where(col(ArticleModel.status).in_([3, 4]))
    rows = session.exec(sql).all()

NOT IN

集合に含まれない値のレコードを取得します。

not_in_querypy
from sqlmodel import Session, col, select
from app.models import ArticleModel

def not_in_query(session: Session) -> None:
    """status が 3,4 以外のレコードを取得する (NOT IN)"""
    print("[not_in_query] status NOT IN (3, 4)")
    sql = select(ArticleModel).where(col(ArticleModel.status).not_in([3, 4]))
    # もしくは
    # sql = select(ArticleModel).where(~col(ArticleModel.status).in_([3, 4]))
    rows = session.exec(sql).all()

LIKE

部分一致するレコードを取得します。

like_querypy
from sqlmodel import Session, col, select
from app.models import ArticleModel

def like_query(session: Session) -> None:
    """title が部分一致するレコードを取得する (LIKE)"""
    print("[like_query] title LIKE '%テスト%'")
    sql = select(ArticleModel).where(col(ArticleModel.title).like("%テスト%"))
    rows = session.exec(sql).all()

番外編

CONTAINS

指定した文字列を含むレコードを取得します。

contain_querypy
from sqlmodel import Session, col, select
from app.models import ArticleModel

def contains_query(session: Session) -> None:
    """title が指定文字列を含むレコードを取得する (contains: 内部的に LIKE を組み立て)"""
    print("[contains_query] title contains 'テスト'")
    sql = select(ArticleModel).where(col(ArticleModel.title).contains("テスト"))
    rows = session.exec(sql).all()
STARTSWITH

指定した文字列で始まるレコードを取得します。

startswith_querypy
from sqlmodel import Session, col, select
from app.models import ArticleModel

def startswith_query(session: Session) -> None:
    """title が指定文字列で始まるレコードを取得する (startswith: 内部的に LIKE)"""
    print("[startswith_query] title startswith 'テスト'")
    sql = select(ArticleModel).where(col(ArticleModel.title).startswith("テスト"))
    rows = session.exec(sql).all()
ENDSWITH

指定した文字列で終わるレコードを取得します。

endswith_querypy
from sqlmodel import Session, col, select
from app.models import ArticleModel

def endswith_query(session: Session) -> None:
    """title が指定文字列で終わるレコードを取得する (endswith: 内部的に LIKE)"""
    print("[endswith_query] title endswith 'テスト'")
    sql = select(ArticleModel).where(col(ArticleModel.title).endswith("テスト"))
    rows = session.exec(sql).all()

ILIKE

大文字・小文字を区別せずに部分一致するレコードを取得します。

ilike_querypy
from sqlmodel import Session, col, select
from app.models import ArticleModel

def ilike_query(session: Session) -> None:
    """title が大文字小文字を無視して部分一致するレコードを取得する (ILIKE 相当)

    DB 方言により生成される SQL が変わります (PostgreSQL なら ILIKE など)
    """
    print("[ilike_query] title ILIKE '%test%' (DB方言により変化)")
    sql = select(ArticleModel).where(col(ArticleModel.title).ilike("%test%"))
    rows = session.exec(sql).all()

AND

複数の条件を連結し、AND条件でレコードを取得します。

and_query
from sqlmodel import Session, col, select
from app.models import ArticleModel

def and_query(session: Session) -> None:
    """複数の where を連結して AND 条件で取得する。"""
    print("[and_query] (status IN (3,4)) AND (title LIKE '%テスト%')")
    sql = (
        select(ArticleModel)
        .where(col(ArticleModel.status).in_([3, 4]))
        .where(col(ArticleModel.title).like("%テスト%"))
    )
    rows = session.exec(sql).all()

OR

OR条件でレコードを取得します。

or_query
from sqlmodel import Session, col, select
from app.models import ArticleModel

def or_query(session: Session) -> None:
    """OR 条件で取得する"""

    print("[or_query] (status = 3) OR (title LIKE '%テスト%')")
    sql = select(
        ArticleModel
    ).where(
        (ArticleModel.status == 3)|(col(ArticleModel.title).like("%テスト%"))
    )
    rows = session.exec(sql).all()

ORDER BY句 / LIMIT句 / OFFSET句

並び替えとページングを行い、レコードを取得します。

order_limit_offset_query.py
from sqlmodel import Session, col, select
from app.models import ArticleModel

def order_limit_offset_query(session: Session) -> None:
    """並び替え+ページング (ORDER BY / LIMIT / OFFSET)

    ArticleModel に `id` カラムがある場合のみ実行します。
    """

    print("[order_limit_offset_query] ORDER BY id DESC LIMIT 5 OFFSET 0")
    sql = select(ArticleModel).order_by(col(ArticleModel.id).desc()).limit(5).offset(0)
    rows = session.exec(sql).all()

終わりに

まだメジャーバージョンではないので情報が古くなる可能性が高いですが、
SQLModel使用時の助けになれば幸いです。

GitHubで編集を提案

Discussion