rtp*_*tpg 9 django postgresql django-queryset
我正在尝试使用django的queryset API来模拟以下查询:
SELECT EXTRACT(year FROM chosen_date) AS year,
EXTRACT(month FROM chosen_date) AS month,
date_paid IS NOT NULL as is_paid FROM
(SELECT (CASE WHEN date_due IS NULL THEN date_due ELSE date END) AS chosen_date,* FROM invoice_invoice) as t1;
Run Code Online (Sandbox Code Playgroud)
这个想法主要是在某些情况下,我宁愿在某些情况下使用date_due
列而不是date
列,但是,因为date_due
是可选的,我有时必须使用date
作为后备,并创建一个计算列chosen_date
,而不必更改其余查询.
这是我在模仿这个时做的第一次尝试,我无法真正看到如何正确地使用基础api进行null测试,所以我选择了extra
:
if(use_date_due):
sum_qs = sum_qs.extra(select={'chosen_date': 'CASE WHEN date_due IS NULL THEN date ELSE date_due END'})
else:
sum_qs = sum_qs.extra(select={'chosen_date':'date'})
sum_qs = sum_qs.extra(select={'year': 'EXTRACT(year FROM chosen_date)',
'month': 'EXTRACT(month FROM chosen_date)',
'is_paid':'date_paid IS NOT NULL'})
Run Code Online (Sandbox Code Playgroud)
但我遇到的问题是当我运行第二个查询时,我得到一个关于chosen_date
列不存在的错误.我在以后尝试使用计算列时遇到过类似的错误(比如在annotate()
调用中),但是在文档中没有找到有关计算列与"基数"列有何不同的内容.有没有人对此有任何见解?
(编辑python代码,因为以前的版本有一个明显的逻辑缺陷(忘了else分支).仍然无法工作)
简短回答:
如果使用extra(select=...)
则创建别名(或计算)列,则无法在后续调用中使用别名列filter()
.此外,正如您所发现的,您不能在以后调用extra(select=...)
或使用别名列
extra(where=...)
.
试图解释原因:
例如:
qs = MyModel.objects.extra(select={'alias_col': 'title'})
#FieldError: Cannot resolve keyword 'alias_col' into field...
filter_qs = qs.filter(alias_col='Camembert')
#DatabaseError: column "alias_col" does not exist
extra_qs = qs.extra(select={'another_alias': 'alias_col'})
Run Code Online (Sandbox Code Playgroud)
filter_qs
将尝试生成如下查询:
SELECT (title) AS "alias_col", "myapp_mymodel"."title"
FROM "myapp_mymodel"
WHERE alias_col = "Camembert";
Run Code Online (Sandbox Code Playgroud)
和extra_qs
尝试是这样的:
SELECT (title) AS "alias_col", (alias_col) AS "another_alias",
"myapp_mymodel"."title"
FROM "myapp_mymodel";
Run Code Online (Sandbox Code Playgroud)
这些都不是有效的SQL.通常,如果要在查询的SELECT或WHERE子句中多次使用计算列的别名,则实际上每次都需要计算它.这就是为什么Roman Pekar的答案可以解决您的具体问题 - 而不是尝试计算chosen_date
一次然后再次使用它,他每次需要时都会计算它.
您在提问中提到了注释/聚合.你可以使用filter()
创建的别名annotate()
(所以我有兴趣看到你正在谈论的类似错误,在我的经验中它是相当强大的).这是因为当您尝试过滤注释创建的别名时,ORM会识别您正在执行的操作,并使用创建它的计算替换别名.
举个例子:
qs = MyModel.objects.annotate(alias_col=Max('id'))
qs = qs.filter(alias_col__gt=0)
Run Code Online (Sandbox Code Playgroud)
产生类似的东西:
SELECT "myapp_mymodel"."id", "myapp_mymodel"."title",
MAX("myapp_mymodel"."id") AS "alias_col"
FROM "myapp_mymodel"
GROUP BY "myapp_mymodel"."id", "myapp_mymodel"."title"
HAVING MAX("myapp_mymodel"."id") > 0;
Run Code Online (Sandbox Code Playgroud)
使用"HAVING MAX alias_col> 0"将不起作用.
我希望这很有帮助.如果有什么我已经解释得很糟糕让我知道,我会看看我是否可以改进它.
归档时间: |
|
查看次数: |
1472 次 |
最近记录: |