我尝试检索发布版本的最大版本,如果资源没有发布版本,则检索最高版本。我使用3个CTE来查找这些值,一个用于获取发布的最大版本,第二个用于获取总体最大版本,最后第三个用于执行外部连接,如果存在最高发布版本,则生成最高发布版本,如果不存在最高版本。
我在SQLAlchemy中遇到的问题是试图连接前2个CTE,以便我可以为版本的每个父版本生成一个结果。
预期的查询如下所示:
WITH highest_published AS (
SELECT parent_id AS parent_id, MAX(subversion) AS m_version
FROM child_version
WHERE published AND NOT deleted
GROUP BY parent_id
),
highest_unpublished AS (
SELECT parent_id AS parent_id, MAX(subversion) AS m_version
FROM child_version
WHERE NOT deleted
GROUP BY parent_id
),
max_versions AS (
SELECT
CASE WHEN hp.parent_id IS NOT NULL THEN hp.parent_id ELSE hu.parent_id END AS parent_id,
CASE WHEN hp.m_version IS NOT null THEN hp.m_version ELSE hu.m_version END AS m_version
FROM highest_unpublished AS hu
LEFT OUTER JOIN highest_published AS hp ON hp.parent_id=hu.parent_id
)
SELECT child_version.id, child_version.parent_id FROM child_version
JOIN max_versions ON child_version.parent_id=max_versions.parent_id
AND child_version.subversion=max_versions.m_version
ORDER BY child_version.parent_id
这是使用ORM的SA代码,我希望生成以下代码:
from sqlalchemy.dialects.postgresql import UUID
import uuid
class ChildVersion(db.Model):
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
deleted = db.Column(db.Boolean, default=False, nullable=False)
parent_id = db.Column(UUID(as_uuid=True), db.ForeignKey(Parent.id), nullable=True, index=True)
subversion = db.Column(db.Integer, default=0, nullable=False)
published = db.Column(db.Boolean, default=False, nullable=False)
highest_published_version = ChildVersion.query.with_entities(
ChildVersion.parent_id.label('parent_id'),
sa.func.max(ChildVersion.subversion).label('m_version'),
).filter(
ChildVersion.published, ~ChildVersion.deleted
).group_by(ChildVersion.parent_id).cte(name='highest_published')
highest_unpublished_version = ChildVersion.query.with_entities(
ChildVersion.parent_id.label('parent_id'),
sa.func.max(ChildVersion.subversion).label('m_version'),
).filter(
~ChildVersion.deleted
).group_by(ChildVersion.parent_id).cte(name='highest_unpublished')
versions = db.session.query(highest_unpublished_version).with_entities(
sa.case(
(highest_published_version.c.parent_id.is_not(None), highest_published_version.c.parent_id),
else_=highest_unpublished_version.c.parent_id).label('parent_id'),
sa.case(
(highest_published_version.c.m_version.is_not(None), highest_published_version.c.m_version),
else_=highest_unpublished_version.c.m_version).label('m_version'),
).join(highest_published_version, sa.and_(highest_unpublished_version.c.parent_id==highest_published_version.c.parent_id,
highest_unpublished_version.c.m_version==highest_published_version.c.m_version),
isouter=True
).cte(name='max_versions')
但是,我收到一个错误,其中我的连接是不明确的:
Don't know how to join to <sqlalchemy.sql.selectable.CTE at 0x10b2c3ee0; highest_published>. Please use the
.select_from() method to establish an explicit left side, as well as providing an explicit ON clause if not present
already to help resolve the ambiguity.
Using the sqlalchemy.select to attempt to join the CTE results in invalid SQL.
一个三个三个一个
任何帮助将不胜感激!
2条答案
按热度按时间js81xvg61#
我创建了一个测试脚本,看起来可以工作。没有实际数据很难判断应该发生什么。我直接使用SA,没有 flask 。而且我刚刚为
Parent
类创建了一个存根。我使用了新的select()
和SQLAlchemy版本1.4/2.0。通过SQLAlchemy的
echo=True
生成SQL。llew8vvj2#
我可以按照错误消息中的建议使用select_from来解决这个问题。