数据查询

进行数据查询之前,需要先按照前文的方法获取一个数据库连接会话,在Web服务等需要并行数据库操作的情况下建议使用连接池进行操作。

Query对象代表着一个查询,这是由Session的query()方法创建的。query()方法中可以列举要查询的类名称,或者类属性名称,例如session.query(User)或者session.query(User.id)。如果是采用经典式模型定义,则Query对象是由模型的查询方法创建的。Query对象返回的查询结果都是命名元组类型的,命名元组的键都是各个类中定义的字段。如果排列了多个查询内容,则会使用类名称或者属性名称。具体可参考以下示例:

for row in session.query(User, User.name).all():
	print(row.User, row.name)

使用sqlalchemy.orm模块中的aliased()函数可以为查询目标定义别名,定义之后需要使用别名在查询中进行访问。

查询筛选

筛选条件是查询中的主要内容,也是最常用的内容。Query对象使用filter()方法来对查询目标进行过滤,filter()方法接受一个布尔表达式。多个filter()方法连续使用表示各个筛选条件之间以and连接。此外还可以从sqlalchemy模块中引入and_()or_()方法来组装andor条件。

大部分条件都定义在Column对象上,常用的有:

  • query.filter(User.id == id),判断相等;
  • query.filter(User.id != id),判断不相等;
  • query.filter(User.name.like('%th%')),区分大小写的LIKE判断;
  • query.filter(User.name.ilike('%th%')),不区分大小写的LIKE判断;
  • query.filter(User.name.in_(['jack', 'kate'])),是否在列表或者子查询中的判断;
  • query.filter(~User.name.in_(['jack', 'kate'])),是否不在列表或者子查询中的判断;
  • query.filter(User.name.is_(None)),判断是否为空;
  • query.filter(User.name.isnot(None)),判断是否为非空;
  • query.filter(and_(User.name == 'a', User.age < 20)),AND条件联合;
  • query.filter(User.name == 'a', User.age < 20),AND条件联合;
  • query.filter(User.name == 'a').filter(User.age < 20),AND条件联合;
  • query.filter(or_(User.name == 'a', User.age < 20)),OR条件联合。

还可以直接使用原生SQL文字来书写比较繁琐的查询条件,如果其中需要参数,可以使用params()方法传递相应的参数进去。例如:

session.query(User).filter(text('age>:minage and age<:maxage')).params(minage=10, maxage=25).all()

获取查询内容

查询需要使用以下方法来获取查询的结果。

  • .all(),获取全部结果,返回一个列表;
  • .first(),获取第一条数据,返回一个表示行的命名元组;
  • .one(),获取一条数据,如果结果不唯一或者无结果会报错;
  • .one_or_none(),获取一条数据,如果结果为空不会报错;
  • .scalar(),与.one()类似,但返回第一列的内容;
  • .count(),返回结果集长度。

对于排序和分组,可以使用Query对象的.order_by().group_by()方法,使用方式很简单,只需要传入要操作的列即可。.order_by()默认采用升序排列,如果需要降序,可以使用Column类中的.desc()方法来声明,当然升序也可以使用.asc()方法来显式声明。例如:query.order_by(User.age.desc())

关联查询

关联查询是数据库查询的一项重要内容。SQLAlchemy提供了多种方法来完成关联查询。

如果不打算使用显式的.join()方法,可以直接将要关联查询的映射类都放在.query()方法中。SQLAlchemy将返回条件合适的元组供使用。例如:

for u, r in session.query(User, Role).filter(User.id==Role.user_id).all();
	print(u)
	print(r)

如果使用.join()方法,则会将被关联的子表结果放在定义的关联映射里。

for u in session.query(User).join(Role).all():
	print(u)

.join()方法还有若干使用方式,可以自动推断如何建立关联。

  • query.join(Role, User.id==Role.user_id),显式条件关联;
  • query.join(User.roles),从左至右的关联定义;
  • query.join(Role, User.roles),同上,显式指定关联目标;
  • query.join('roles'),同上,以字符串指定关联目标。