3

我正在尝试使用 Django ORM 表达以下(Postgres)SQL 语句:

SELECT 
    v.id, v.min_salary, v.max_salary, v.min_weekly_hours, v.max_weekly_hours
    p.min_start_date, p.max_end_date
FROM 
    vacancy v,
    (
        SELECT 
        id, vacancy_id, MIN(start_date) min_start_date, MAX(end_date) AS max_end_date 
        FROM vacancypublication
        WHERE (active = True AND site_id = 1 AND start_date <= CURRENT_TIMESTAMP) 
        GROUP BY id, vacancy_id
    ) p
WHERE  
    p.vacancy_id = v.id AND
    v.workflow_status = 'A'
ORDER BY p.min_start_date DESC;

问题是我在 FROM 子句中使用了子查询(也称为“内联视图”)。

我尝试过使用.extra(tables=['...']),但 Django 在语句中添加了引号,使 SQL 无效。

我宁愿不求助于.raw查询。有没有办法做到这一点?如果核心 API 没有提供方法,也许可以通过可重用的应用程序。

编辑

这是使用连接的(看似)等效语句:

    SELECT
    v.id, v.code, v.min_salary, v.max_salary, v.min_weekly_hours, v.max_weekly_hours, v.application_email, v.application_url, v.available_positions,
    MIN(CASE WHEN (p.active = True AND p.site_id = 1 AND p.start_date <= CURRENT_TIMESTAMP) THEN p.start_date ELSE NULL END) AS start_date, 
    MAX(CASE WHEN (p.active = True AND p.site_id = 1) THEN p.end_date ELSE NULL END) AS end_date
FROM base_vacancy v 
LEFT OUTER JOIN 
    base_vacancypublication p ON v.id = p.vacancy_id
WHERE v.workflow_status = 'A'
GROUP BY v.id, v.code, v.min_salary, v.max_salary, v.min_weekly_hours, v.max_weekly_hours, v.application_email, v.application_url, v.available_positions
HAVING MIN(CASE WHEN (p.active = True AND p.site_id = 1 AND p.start_date <= CURRENT_TIMESTAMP) THEN p.start_date ELSE NULL END) IS NOT NULL 
ORDER BY start_date DESC;

它的速度大约慢了 3 倍,但可以使用 Django 1.9 ORM 方法来编写它:

Vacancy.objects.annotate(
    start_date=Min(
        Case(
            When(publication_set__is_active=True, publication_set__site_id=1, publication_set__start_date__lte=Now(), then='publication_set__start_date'),
            default=None
        )
    ),
    end_date=Max(
        Case(
            When(publication_set__is_active=True, publication_set__site_id=1, then='publication_set__end_date'),
            default=None
        )
    )
).filter(
    start_date__isnull=False, status=Workflow.APPROVED
).order_by(
    '-start_date'
)
4

0 回答 0