【问题标题】:How to use postgresql's jsonb_each function with sqlalchemy's ORM如何在 sqlalchemy 的 ORM 中使用 postgresql 的 jsonb_each 函数
【发布时间】:2019-01-22 15:29:11
【问题描述】:

我正在尝试编写一个函数来通过 sqlalchemy 计算 postgres 中嵌套 json 值的平均值。我要平均的值在统计表中,其中包含一个包含这样的 json 字典的分数列(过滤到相关结构): {1: {'score': 0.0}, 2: {'score' : 0.0} ...}。

用postgres编写,查询如下:

SELECT *, avg((v->>'score')::float) AS average_score
FROM lms.statistics, jsonb_each(statistics.scores) js(k, v)
WHERE jsonb_typeof(scores) != 'null'
GROUP BY statistics.id

我主要将其转换为以下 sqlalchemy 代码:

(
  session.query(Statistics)
  .add_columns(literal_column("avg((v->>'score')::float)").label('average_score'))
  .filter(literal("jsonb_typeof(statistics.scores != 'null'"))
  .group_by(Statistics.id)
).all()

但是,无论我尝试做什么,sqlalchemy 都不允许我包含此查询所依赖的 jsonb_each。我什至尝试重组查询以使用显式连接,而 sqlalchemy 的 .join 不会接受literal_column、文本或任何带有外部连接或指定假连接条件的诡计。当必须有一个 sqlalchemy 标准来将纯文本查询插入 FROM 或 JOIN 语句时,我已经走到尽头了。

【问题讨论】:

    标签: postgresql sqlalchemy


    【解决方案1】:

    对于返回标量或单列集的函数,您只需使用func.something.alias('x')column('x')。不幸的是,SQLAlchemy 不支持显式地对列进行别名,因此处理返回多列组合的函数有点棘手。如果是jsonb_each the default names are key and value,那么你可以使用这些:

    v = column('value', type_=JSONB)
    score = v['score'].astext.cast(Float)
    
    session.query(Statistics,
                  func.avg(score).label('average_score')).\
        select_from(Statistics,
                    func.jsonb_each(Statistics.scores).alias()).\
        filter(func.jsonb_typeof(Statistics.scores) != 'null').\
        group_by(Statistics.id)
    

    【讨论】:

    • 这很好用!不幸的是,有了这个错误,我实际上意识到我希望在连接条件下使用它。因为我实际上是在添加到以前定义的查询中,因此在 FROM 已经定义的地方得到了错误。但是....这会导致 sqlalchemy 抛出这个:“sqlalchemy.exc.NotSupportedError: (psycopg2.NotSupportedError) set-returning functions are not allowed in JOIN conditions”。但是,我知道情况并非如此,因为我已经在 postgres 中使用完全外部联接编写了查询,并且它工作得很好。对此有何建议?
    • 首先想到的是您是否试图在 ON 子句中放置一个集合返回函数(而不是横向连接)? “希望在连接条件中使用它”是什么意思?您可以将现有查询包装为子查询并加入吗?听起来你可能有一个新问题的气质:P
    • 啊。知道了。对于未来的读者,我可以将它移动到这样的连接中:.outerjoin(func.jsonb_each(Statistics.scores).alias(), text('true'))
    猜你喜欢
    • 2015-05-05
    • 1970-01-01
    • 2019-05-18
    • 2021-07-06
    • 2022-01-12
    • 1970-01-01
    • 2017-07-31
    • 2018-04-19
    • 2021-01-17
    相关资源
    最近更新 更多