如何使用sqlalchemy orm实现子选择?

时间:2018-07-30 10:35:36

标签: python sqlalchemy

我有以下型号:

  • 相册:ID,名称,...
  • 曲目:id,album_id,...

我需要使用SQLAlchemy orm生成以下查询:

SELECT 
  Album.name,
  (
    SELECT COUNT(*) as total_count
    FROM Track
    WHERE Track.album_id = Album.id
  ) as tracks
FROM
  Album
WHERE
  Album.band = ‘Metallica’ AND
  tracks.total_count > 10

到目前为止的代码:

tracks = session \
  .query(func.count('*').label('total_count')) \
  .select_from(Track) \
  .filter(Track.album_id == Album.id) \
  .subquery()

query = session \
  .query(Album.name, tracks.c.total_count) \
  .filter(Album.band == 'Metallica') \
  .filter(tracks.c.total_count > 10)

,生成的查询如下:

SELECT
  Album.name,
  anon_1.total_count
FROM
  Album,
  (
    SELECT count('*') AS total_count
    FROM Track, Album
    WHERE Track.album_id = Album.id
  ) AS anon_1
WHERE
  Album.band = ‘Metallica’ AND
  anon_1.total_count > 10

这要慢得多。有什么想法我可以作为根选择的一部分返回子选择的结果吗?谢谢!

1 个答案:

答案 0 :(得分:1)

您无法执行所需的查询,因为您无法在WHERE子句谓词中使用选择列表项,因为WHERE在SELECT之前进行求值。在这种情况下,普通的JOIN,GROUP BY和HAVING就足够了:

query = session \
  .query(Album.name, func.count()) \
  .join(Track) \
  .filter(Album.band == 'Metallica') \
  .group_by(Album.id) \
  .having(func.count() > 10)

上面的查询使用的事实是,即使GROUP BY中未使用Album.name,也应选择Album.id,因为它在功能上依赖于private String courses; 。当然,鉴于没有相册共享名称,您也可以按名称分组。

您最初的尝试很慢,因为它没有在关联的子查询中执行专辑和曲目之间的子查询中的SQL-92风格的联接,有效地计数了所有曲目,并再次在专辑和封闭查询中的派生表之间进行了联接。