将 SQL 转换为 SQLAlchemy

问题描述 投票:0回答:1

我有一个表,

books
,有多个列,其中一列
categories
是一个字符串数组

select * from books where exists (select * from (select  unnest(books.categories)) x(categories) where x.categories ilike 'fiction%');

将其转换为 SQLAlchemy 查询字符串时遇到很多麻烦。我想做的是获取至少有一个以“小说”一词开头的类别的所有书籍。

(下面的简单查询不起作用,这只是为了让您可以轻松理解我想要通过上面的复杂查询实现的目标)

select categories from books where 'fiction%' ilike any(categories);
sql sqlalchemy flask-sqlalchemy
1个回答
0
投票

您需要列值函数,以下是重要的行。

column_valued = func.unnest(Book.categories).column_valued()
statement = select(Book).where(select(column_valued).where(column_valued.ilike('fiction%')).exists())

代码生成以下sql

SELECT books.id, books.name, books.categories 
FROM books 
WHERE EXISTS (SELECT anon_1 
FROM unnest(books.categories) AS anon_1 
WHERE anon_1 ILIKE %(param_1)s::VARCHAR)

这是一个完整的示例,显示了您想要的内容。

from sqlalchemy import create_engine, select, func, String
from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column
from sqlalchemy.dialects.postgresql import ARRAY

class Base(DeclarativeBase):
    pass

class Book(Base):
    __tablename__ = 'books'
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    categories: Mapped[list[str]] = mapped_column(ARRAY(String))

engine = create_engine("connection string")
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)

with Session(engine) as session:
    # insert sample test data
    session.add(Book(name='Book 1', categories=['fiction', 'mystery', 'romance', 'adventure']))  # just fiction
    session.add(Book(name='Book 2', categories=['historical', 'horror']))  # no fiction
    session.add(Book(name='Book 3', categories=['fiction historical', 'horror']))  # starts with fiction
    session.add(Book(name='Book 4', categories=['horror']))  # no fiction
    session.add(Book(name='Book 5', categories=['fiction romance', 'horror']))  # starts with fiction
    session.commit()

with Session(engine) as session:
    column_valued = func.unnest(Book.categories).column_valued()
    statement = select(Book).where(
        select(column_valued).where(column_valued.ilike('fiction%')).exists()
    )

    for i in session.scalars(statement):
        print(i.name)

输出

Book 1
Book 3
Book 5

所有类别均不以

fiction
开头的书籍不会显示在此处,我相信这就是您想要的。

© www.soinside.com 2019 - 2024. All rights reserved.