我正在使用Flask-SQLAlchemy,并且使用一对多关系。两种型号
airflow worker -q spark
我需要确定哪个买方的所有需求最少 的买家。
我可以通过创建其他列表并将所有 列表中的请求并搜索列表。但是我相信还有另一种简单的方法可以通过SQLAlchemy查询
答案 0 :(得分:1)
您可以使用CTE(公用表表达式)来执行此操作,以产生买方ID及其请求计数,因此
buyer_id | request_count :------- | :------------ 1 | 5 2 | 3 3 | 1 4 | 1
您可以在此处过滤必须大于0的要列出的计数。
然后您可以将其与Buyers表结合以产生:
buyer_id | buyer_name | buyer_email | request_count :------- | :--------- | :--------------- | :------------ 1 | foo | foo@example.com | 5 2 | bar | bar@example.com | 3 3 | baz | baz@example.com | 1 4 | spam | spam@example.com | 1
但是由于我们使用的是CTE,因此您也可以向CTE查询最低计数值。在上面的示例中,这是1
,您可以在合并的带计数的购买者查询中添加一个WHERE
子句,以将结果过滤到仅request_count
值的行等于该最小值。
对此的SQL查询是
WITH request_counts AS (
SELECT request.buyer_id AS buyer_id, count(request.id) AS request_count
FROM request GROUP BY request.buyer_id
HAVING count(request.id) > ?
)
SELECT buyer.*
FROM buyer
JOIN request_counts ON buyer.id = request_counts.buyer_id
WHERE request_counts.request_count = (
SELECT min(request_counts.request_count)
FROM request_counts
)
WITH request_counts AS (...)
定义了CTE,而该部分将生成带有buyer_id
和request_count
的第一张表。然后,request_count
表与request
结合在一起,并且WHERE
子句对min(request_counts.request_count)
值进行过滤。
将以上内容翻译为Flask-SQLAlchemy代码:
request_count = db.func.count(Request.id).label("request_count")
cte = (
db.select([Request.buyer_id.label("buyer_id"), request_count])
.group_by(Request.buyer_id)
.having(request_count > 0)
.cte('request_counts')
)
min_request_count = db.select([db.func.min(cte.c.request_count)]).as_scalar()
buyers_with_least_requests = Buyer.query.join(
cte, Buyer.id == cte.c.buyer_id
).filter(cte.c.request_count == min_request_count).all()
演示:
>>> __ = db.session.bulk_insert_mappings(
... Buyer, [{"name": n} for n in ("foo", "bar", "baz", "spam", "no requests")]
... )
>>> buyers = Buyer.query.order_by(Buyer.id).all()
>>> requests = [
... Request(buyer_id=b.id)
... for b in [*([buyers[0]] * 3), *([buyers[1]] * 5), *[buyers[2], buyers[3]]]
... ]
>>> __ = db.session.add_all(requests)
>>> request_count = db.func.count(Request.id).label("request_count")
>>> cte = (
... db.select([Request.buyer_id.label("buyer_id"), request_count])
... .group_by(Request.buyer_id)
... .having(request_count > 0)
... .cte("request_counts")
... )
>>> buyers_w_counts = Buyer.query.join(cte, cte.c.buyer_id == Buyer.id)
>>> for buyer, count in buyers_w_counts.add_column(cte.c.request_count):
... # print out buyer and request count for this demo
... print(buyer, count, sep=": ")
<Buyer foo>: 3
<Buyer bar>: 5
<Buyer baz>: 1
<Buyer spam>: 1
>>> min_request_count = db.select([db.func.min(cte.c.request_count)]).as_scalar()
>>> buyers_w_counts.filter(cte.c.request_count == min_request_count).all()
[<Buyer baz>, <Buyer spam>]
我还创建了一个数据库<>小提琴here,其中包含相同的查询以供使用。