继续here。
我在Django中有以下查询表达式:
Connection.prototype.query = function query(sql, values, cb) {
var query = Connection.createQuery(sql, values, cb);
query._connection = this;
if (!(typeof sql == 'object' && 'typeCast' in sql)) {
query.typeCast = this.config.typeCast;
}
if (query.sql) {
query.sql = this.format(query.sql, query.values);
}
this._implyConnect();
return this._protocol._enqueue(query);
};
这可以正确计算按fields = {
'impressions': models.Sum('impressions'),
'clicks': models.Sum('clicks'),
}
calc_fields = {
'ctr': models.Case(models.When(impressions = 0, then = 0), default = 1.0 * models.F('clicks') / models.F('impressions'), output_field = models.FloatField()),
}
Stats.objects.values('product').annotate(**fields).annotate(**calc_fields)
分组的汇总字段impressions
,clicks
和ctr
,并生成以下postgres查询:
product
现在我想要的是修改这个表达式,这样当没有提供分组时,它只会在整个表中返回聚合值。
它似乎比我预期的更难。问题的其余部分可以跳过,我只是列出我尝试过的内容。
1)首先尝试放弃SELECT
"stats"."product_id",
SUM("stats"."impressions") AS "impressions",
SUM("stats"."clicks") AS "clicks",
CASE WHEN SUM("stats"."impressions") = 0 THEN 0 ELSE ((1.0 * SUM("stats"."clicks")) / SUM("stats"."impressions")) END AS "ctr"
FROM "stats"
GROUP BY "stats"."product_id";
:
values()
这会产生错误:
Stats.objects.annotate(**fields).annotate(**calc_fields)
这可能是因为它现在尝试返回包含其所有字段的完整The annotation 'impressions' conflicts with a field on the model.
对象的列表,而不是仅返回我之前列出的自定义字段。也许有一种方法可以禁用它并返回自定义字段?
我尝试重命名字段,但它会导致主索引分组,因此它返回表中的所有记录而不是一个
2)也许我需要将注释与聚合交换。
Stats
这会产生错误:
Stats.objects.aggregate(**fields).aggregate(**calc_fields)
好吧也许他们无法链接,让我们将这些字段合并在一起,并在案例中与Error: 'dict' object has no attribute 'aggregate'
交换F
:
Sum
这似乎工作正常。但是当我添加额外的字段时,地狱再次破裂(所有值都相同,只有名称不同):
fields = {
'impressions': models.Sum('impressions'),
'clicks': models.Sum('clicks'),
'ctr': models.Case(models.When(impressions = 0, then = 0), default = 1.0 * models.Sum('clicks') / models.Sum('impressions'), output_field = models.FloatField()),
}
Stats.objects.aggregate(**fields)
似乎问题是由多个fields = {
'impressions': models.Sum('impressions'),
'impressions2': models.Sum('impressions'),
'clicks': models.Sum('clicks'),
'clicks2': models.Sum('clicks'),
'ctr': models.Case(models.When(impressions = 0, then = 0), default = 1.0 * models.Sum('clicks') / models.Sum('impressions'), output_field = models.FloatField()),
'ctr2': models.Case(models.When(impressions = 0, then = 0), default = 1.0 * models.Sum('clicks') / models.Sum('impressions'), output_field = models.FloatField()),
}
引起的,它会生成错误的sql:
models.When(impressions = 0)
请注意SELECT
CASE WHEN "stats"."impressions" = 0 THEN 0 ELSE ((1.0 * SUM("stats"."clicks")) / SUM("stats"."impressions")) END AS "ctr",
CASE WHEN SUM("fstats"."impressions") = 0 THEN 0 ELSE ((1.0 * SUM("stats"."clicks")) / SUM("impressions")) END AS "ctr2",
SUM("stats"."impressions") AS "impressions",
SUM("stats"."impressions") AS "impressions2",
SUM("stats"."clicks") AS "clicks",
SUM("stats"."clicks") AS "clicks2",
FROM "stats";
的CASE如何被错误地计算为:
ctr
虽然CASE WHEN "stats"."impressions" = 0
是正确的:
ctr2
导致数据库错误:
CASE WHEN SUM("stats"."impressions") = 0
3)将所有聚合字段重命名为与模型字段不同,这样就不会产生混淆:
column "stats.impressions" must appear in the GROUP BY clause or be used in an aggregate function
这会产生错误:
fields = {
'impressions_total': models.Sum('impressions'),
'impressions_total2': models.Sum('impressions'),
'clicks_total': models.Sum('clicks'),
'clicks_total2': models.Sum('clicks'),
'ctr': models.Case(models.When(impressions_total = 0, then = 0), default = 1.0 * models.Sum('clicks') / models.Sum('impressions'), output_field = models.FloatField()),
'ctr2': models.Case(models.When(impressions_total = 0, then = 0), default = 1.0 * models.Sum('clicks') / models.Sum('impressions'), output_field = models.FloatField()),
}
Stats.objects.aggregate(**fields)
如果我在没有Error: Cannot resolve keyword 'impressions_total' into field. Choices are: clicks, clicks_total, impressions, impressions_total2, product, product_id
的情况下离开单ctr
,它就可以了。再次添加额外字段会因某种原因而中断。
任何提示?我希望它只返回一个自定义字段数组而不是完整对象。