【问题标题】:Changing where clause without generating subquery in SQLAlchemy在 SQLAlchemy 中更改 where 子句而不生成子查询
【发布时间】:2013-08-28 02:49:38
【问题描述】:

我正在尝试构建一个相对复杂的查询,并希望直接操作结果的 where 子句,而不是克隆/子查询返回的查询。一个示例如下所示:

    session = sessionmaker(bind=engine)()

    def generate_complex_query():
        return select(
            columns=[location.c.id.label('id')], 
            from_obj=location,
            whereclause=location.c.id>50
        ).alias('a')

    query = generate_complex_query()
    # based on this query, I'd like to add additional where conditions, ideally like:
    # `query.where(query.c.id<100)`
    # but without subquerying the original query

    # this is what I found so far, which is quite verbose and it doesn't solve the subquery problem
    query = select(
        columns=[query.c.id],
        from_obj=query,
        whereclause=query.c.id<100
    )

    # Another option I was considering was to map the query to a class:
    #   class Location(object):pass
    #   mapper(Location, query)
    #   session.query(Location).filter(Location.id<100)
    # which looks more elegant, but also creates a subquery

    result = session.execute(query)

    for r in result:
        print r

这是生成的查询:

SELECT a.id 
FROM (SELECT location.id AS id 
FROM location 
WHERE location.id > %(id_1)s) AS a 
WHERE a.id < %(id_2)s

我想获得:

SELECT location.id AS id 
FROM location 
WHERE id > %(id_1)s and
id < %(id_2)s

有什么方法可以实现吗?这样做的原因是我认为查询 (2) 稍微快一点(不多),并且我已经使用的映射器示例(上面的第二个示例)弄乱了标签(id 变为 anon_1_ida.id如果我命名别名)。

【问题讨论】:

    标签: python sql select sqlalchemy


    【解决方案1】:

    你为什么不这样做:

    query = generate_complex_query()
    query = query.where(location.c.id < 100)
    

    基本上,您可以像这样优化任何查询。此外,我建议阅读SQL Expression Language Tutorial,它非常棒,介绍了您需要的所有技术。您构建select 的方式只是一种方式。通常,我构建的查询更像这样:select(column).where(expression).where(next_expression) 等等。 FROM 通常由 SQLAlchemy 从上下文自动推断,即您很少需要指定它。

    由于您无权访问 generate_complex_query 的内部结构,请尝试以下操作:

    query = query.where(query.c.id < 100)
    

    我想这应该适用于你的情况。

    另一个想法:

    query = query.where(text("id < 100"))
    

    这使用 SQLAlchemy 的 text 表达式。但是,这可能对您有用,这重要:如果您想引入变量,请阅读上面链接的 API 的描述,因为只需使用格式字符串而不是 绑定参数 em> 会让你接触到 SQL 注入,这通常是使用 SQLAlchemy 不费吹灰之力的事情,但在使用此类文字表达式时必须小心。

    还请注意,这是有效的,因为您将列标记为 id。如果您不这样做并且不知道列名,那么这也不起作用。

    【讨论】:

    • 查询结果是什么?多个嵌套子查询或“与”的 where 子句?
    • 啊...您使用location.c.id 作为要选择的列。不幸的是,我对generate_complex_query 中发生的事情没有任何见解,因此无法访问它的任何表列...
    • 谢谢@javex。这种方法的问题在于它将原始查询包装到子查询中并创建新的列标签(请参阅我帖子中的第一个查询)。
    • 可能有问题,我正在构建原始查询。我在查询构造函数中返回select(columns=[location.c.id.label('id')], from_obj=location, whereclause=location.c.id &gt; 50)
    • @orange 不,查询完全没问题。我会以类似方式构建它,从而产生相同的查询。我将添加一种新方法,它可能对您使用文字 SQL 有用。
    猜你喜欢
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多