假设我有一个activity
表和一个subscription
表。每个活动都有对其他某个对象的泛型引用数组,每个订阅都有对同一集中其他某个对象的单个泛型引用。
CREATE TABLE activity (
id serial primary key,
ob_refs UUID[] not null
);
CREATE TABLE subscription (
id UUID primary key,
ob_ref UUID,
subscribed boolean not null
);
我想加入set returning函数
unnest
以便找到“最深”的匹配订阅,如下所示:SELECT id
FROM (
SELECT DISTINCT ON (activity.id)
activity.id,
x.ob_ref, x.ob_depth,
subscription.subscribed IS NULL OR subscription.subscribed = TRUE
AS subscribed,
FROM activity
LEFT JOIN subscription
ON activity.ob_refs @> array[subscription.ob_ref]
LEFT JOIN unnest(activity.ob_refs)
WITH ORDINALITY AS x(ob_ref, ob_depth)
ON subscription.ob_ref = x.ob_ref
ORDER BY x.ob_depth DESC
) sub
WHERE subscribed = TRUE;
但我不知道如何进行第二次连接并访问列。我试过创建一个
FromClause
like this:act_ref_t = (sa.select(
[sa.column('unnest', UUID).label('ob_ref'),
sa.column('ordinality', sa.Integer).label('ob_depth')],
from_obj=sa.func.unnest(Activity.ob_refs))
.suffix_with('WITH ORDINALITY')
.alias('act_ref_t'))
...
query = (query
.outerjoin(
act_ref_t,
Subscription.ob_ref == act_ref_t.c.ob_ref))
.order_by(activity.id, act_ref_t.ob_depth)
但这会导致这个SQL包含另一个子查询:
LEFT OUTER JOIN (
SELECT unnest AS ob_ref, ordinality AS ref_i
FROM unnest(activity.ob_refs) WITH ORDINALITY
) AS act_ref_t
ON subscription.ob_refs @> ARRAY[act_ref_t.ob_ref]
... 因为缺少和unsupported
LATERAL
关键字而失败:表“activity”有一个条目,但不能从查询的这一部分引用它。
那么,如何在不使用子查询的情况下为这个SRF创建JOIN子句呢?或者我还缺什么?
使用
sa.text
而不是TextClause.columns
来编辑1会让我更接近:act_ref_t = (sa.sql.text(
"unnest(activity.ob_refs) WITH ORDINALITY")
.columns(sa.column('unnest', UUID),
sa.column('ordinality', sa.Integer))
.alias('act_ref'))
但结果SQL失败,因为它将子句括在括号中:
LEFT OUTER JOIN (unnest(activity.ob_refs) WITH ORDINALITY)
AS act_ref ON subscription.ob_ref = act_ref.unnest
错误是
sa.select
。我能不能不把syntax error at or near ")"
用圆括号括起来? 最佳答案
这并不是SA直接支持的,但是通过aColumnClause
和aFunctionElement
可以实现正确的行为。第一次导入this recipe如zzzeek中的this SA issue所述。然后创建一个特殊的unnest
函数,其中包含WITH ORDINALITY
修饰符:
class unnest_func(ColumnFunction):
name = 'unnest'
column_names = ['unnest', 'ordinality']
@compiles(unnest_func)
def _compile_unnest_func(element, compiler, **kw):
return compiler.visit_function(element, **kw) + " WITH ORDINALITY"
然后可以在连接、排序等中使用它,例如:
act_ref = unnest_func(Activity.ob_refs)
query = (query
.add_columns(act_ref.c.unnest, act_ref.c.ordinality)
.outerjoin(act_ref, sa.true())
.outerjoin(Subscription, Subscription.ob_ref == act_ref.c.unnest)
.order_by(act_ref.c.ordinality.desc()))
关于postgresql - 与集合返回函数(SRF)和SQLAlchemy中的访问列联接,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33865038/