SQLAlchemy:跨多个表查询

4 投票
2 回答
3365 浏览
提问于 2025-04-16 00:06

我想优化我的数据库查询:

link_list = select(
    columns=[link_table.c.rating, link_table.c.url, link_table.c.donations_in],
    whereclause=and_(
        not_(link_table.c.id.in_(
            select(
                columns=[request_table.c.recipient],
                whereclause=request_table.c.donator==donator.id
            ).as_scalar()
        )),
        link_table.c.id!=donator.id,
    ),
    limit=20,
).execute().fetchall()

于是我尝试把这两个查询合并成一个:

link_list = select(
    columns=[link_table.c.rating, link_table.c.url, link_table.c.donations_in],
    whereclause=and_(
        link_table.c.active==True,
        link_table.c.id!=donator.id,
        request_table.c.donator==donator.id,
        link_table.c.id!=request_table.c.recipient,
    ),
    limit=20,
    order_by=[link_table.c.rating.desc()]
).execute().fetchall()

数据库的结构看起来是这样的:

link_table = Table('links', metadata,
    Column('id', Integer, primary_key=True, autoincrement=True),
    Column('url', Unicode(250), index=True, unique=True),
    Column('registration_date', DateTime),
    Column('donations_in', Integer),
    Column('active', Boolean),
)
request_table = Table('requests', metadata,
    Column('id', Integer, primary_key=True, autoincrement=True),
    Column('recipient', Integer, ForeignKey('links.id')),
    Column('donator', Integer, ForeignKey('links.id')),
    Column('date', DateTime),
)

在请求表(request_table)中,有几个链接(捐赠者)指向链接表(link_table)中的一个链接。我想要获取那些在链接表中还没有被“请求”的链接。

但是这样做不行。我想知道我正在尝试的事情到底可不可以?如果可以的话,你会怎么做呢?

非常感谢你的帮助!

2 个回答

0

参考一下 masida的回答

首先,原始的查询语句是:

>>> print select(
...     columns=[link_table.c.url, link_table.c.donations_in],
...     whereclause=and_(
...         not_(link_table.c.id.in_(
...             select(
...                 columns=[request_table.c.recipient],
...                 whereclause=request_table.c.donator==5
...             ).as_scalar()
...         )),
...         link_table.c.id!=5,
...     ),
...     limit=20,
... )
SELECT links.url, links.donations_in 
FROM links 
WHERE links.id NOT IN (SELECT requests.recipient 
FROM requests 
WHERE requests.donator = :donator_1) AND links.id != :id_1 
 LIMIT 20

然后用exists()的方式重写如下:

>>> print select(
...     columns=[link_table.c.url, link_table.c.donations_in],
...     whereclause=and_(
...     not_(exists().where(request_table.c.donator==5)),
...     #    ^^^^^^^^^^^^^^
...         link_table.c.id!=5,
...     ),
...     limit=20,
... )
SELECT links.url, links.donations_in 
FROM links 
WHERE NOT (EXISTS (SELECT * 
FROM requests 
WHERE requests.donator = :donator_1)) AND links.id != :id_1 
 LIMIT 20
1

你可能在寻找SQL中的NOT EXISTS这个用法:

http://www.sqlalchemy.org/docs/orm/tutorial.html#using-exists

撰写回答