【问题标题】:How can I prevent sqlalchemy from prefixing the column names of a CTE?如何防止 sqlalchemy 为 CTE 的列名添加前缀?
【发布时间】:2013-03-14 17:39:02
【问题描述】:

考虑以下通过 SQLAlchemy 编码的查询。

# Create a CTE that performs a join and gets some values
x_cte = session.query(SomeTable.col1
                     ,OtherTable.col5
                     ) \
               .select_from(SomeTable) \
               .join(OtherTable, SomeTable.col2 == OtherTable.col3)
               .filter(OtherTable.col6 == 34)
               .cte(name='x')

# Create a subquery that splits the CTE based on the value of col1
# and computes the quartile for positive col1 and assigns a dummy
# "quartile" for negative and zero col1
subquery = session.query(x_cte
                        ,literal('-1', sqlalchemy.INTEGER).label('quartile')
                        ) \
                  .filter(x_cte.col1 <= 0)
                  .union_all(session.query(x_cte
                                          ,sqlalchemy.func.ntile(4).over(order_by=x_cte.col1).label('quartile')
                                          )
                                    .filter(x_cte.col1 > 0)
                            ) \
               .subquery()

# Compute some aggregate values for each quartile
result = session.query(sqlalchemy.func.avg(subquery.columns.x_col1)
                      ,sqlalchemy.func.avg(subquery.columns.x_col5)
                      ,subquery.columns.x_quartile
                      ) \
                .group_by(subquery.columns.x_quartile) \
                .all()

对不起,这与我的真实查询相似。在我的真实代码中,我为我的 CTE 赋予了一个更具描述性的名称,并且我的 CTE 有更多的列,我必须为其计算平均值。 (它实际上也是由 CTE 中的一列加权的加权平均值。)

真正的“问题”纯粹是试图让我的代码更清晰、更短。 (是的,我知道。这个查询已经是一个怪物并且难以阅读,但客户坚持认为这些数据是可用的。)请注意,在最后的查询中,我必须将我的列引用为subquery.columns.x_[column name];这是因为 SQLAlchemy 在我的列名前面加上 CTE 名称。我只想让 SQLAlchemy 在生成列名时省略我的 CTE 名称,但由于我有很多列,我不想在我的子查询中单独列出它们。去掉 CTE 名称会使我的列名(它们本身就足够长)更短且更易读;我可以保证这些列是唯一的。我该怎么做?

将 Python 2.7.3 与 SQLAlchemy 0.7.10 结合使用。

【问题讨论】:

    标签: python python-2.7 sqlalchemy


    【解决方案1】:

    您并没有太明确“x_”在这里是什么,但如果这是最终结果,请使用 label() 为结果列指定您想要的任何名称:

    row = session.query(func.avg(foo).label('foo_avg'), func.avg(bar).label('bar_avg')).first()
    foo_avg = row['foo_avg']  # indexed access
    bar_avg = row.bar_avg     # attribute access
    

    编辑:我无法在此处重现“x_”。这是一个测试:

    from sqlalchemy import *
    from sqlalchemy.orm import *
    from sqlalchemy.ext.declarative import declarative_base
    
    Base = declarative_base()
    
    class A(Base):
        __tablename__ = "a"
    
        id = Column(Integer, primary_key=True)
    
        x = Column(Integer)
        y = Column(Integer)
    
    s = Session()
    
    subq = s.query(A).cte(name='x')
    
    subq2 = s.query(subq, (subq.c.x + subq.c.y)).filter(A.x == subq.c.x).subquery()
    
    print s.query(A).join(subq2, A.id == subq2.c.id).\
            filter(subq2.c.x == A.x, subq2.c.y == A.y)
    

    在上面,你可以看到我可以毫无问题地参考subq2.c.&lt;colname&gt;,没有“x”前缀。如果您可以指定 SQLAlchemy 版本信息并完整填写您的示例,我可以按原样运行它以重现您的问题。

    【讨论】:

    • 对不起。当我编写最终查询时,我正在谈论代码。例如,subquery.columns.x_quartile。我会修改问题。
    • 感谢您的帮助。如果在定义subq2 时向结果集中添加另一列怎么办?例如,s.query(subq, (subq.c.x + subq.c.y))。我还在我的问题中添加了版本信息。
    • 已编辑,是的,那里没有问题。有 的东西使 SQLAlchemy 将表名附加到列名,并且有办法处理这个问题,但我没有在你说明的代码 sn-ps 中看到它(除非我有我实际上可以运行的东西)。
    猜你喜欢
    • 2013-01-30
    • 2016-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-05
    • 1970-01-01
    • 2012-06-18
    相关资源
    最近更新 更多