我有一个表,
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);
您需要列值函数,以下是重要的行。
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
开头的书籍不会显示在此处,我相信这就是您想要的。