我应该写哪个 Django ORM 或 raw SQL 来得到我需要的
Which Django ORM or raw SQL should I write to get exactly what I need
我正在使用 Postgresql。我有型号:
class EventsList(CreatedUpdatedMixin):
start = models.DateTimeField()
end = models.DateTimeField()
is_inner = models.BooleanField()
假设我有那些数据库条目:
start
end
is_inner
2021-12-09 14:30:12
2021-12-09 15:00:21
true
2021-12-09 14:00:05
2021-12-10 21:00:15
false
2021-12-10 09:00:39
2021-12-10 09:30:50
true
2021-12-10 14:00:00
2021-12-11 15:00:00
true
2021-12-14 10:00:00
2021-12-14 11:00:00
true
2021-12-13 13:30:00
2021-12-16 14:30:00
false
2021-12-14 13:10:00
2021-12-15 00:30:00
true
2021-12-14 10:30:00
2021-12-16 13:34:00
false
2021-12-15 13:30:00
2021-12-15 18:30:00
true
这就是我需要的结果:
[
{"2021-12-09": {"external_events": 1, "internal_events": 1}},
{"2021-12-10": {"external_events": 0, "internal_events": 2}},
{"2021-12-11": {"external_events": 0, "internal_events": 1}},
{"2021-12-13": {"external_events": 1, "internal_events": 0}},
{"2021-12-14": {"external_events": 2, "internal_events": 2}},
{"2021-12-15": {"external_events": 2, "internal_events": 2}},
{"2021-12-16": {"external_events": 2, "internal_events": 0}},
]
所以我想获取所有现有日期,并为每个日期获取外部事件的计数(其中 is_inner == False)和内部事件的计数(其中 is_inner == True ).
我如何使用 Django ORM 或原始 SQL 来完成?
现在,我想出了
EventsList.objects.annotate(
start_day=Cast("start", output_field=DateField())
).values("start_day").annotate(
external_events=Count("id", filter=Q(is_inner=False)),
internal_events=Count("id", filter=Q(is_inner=True)),
).values(
"start_day", "external_events", "internal_events"
)
此代码 returns 几乎是正确的结果(但仅适用于“开始”日期)。我需要包括所有日期(开始日期、结束日期以及它们之间的所有日期)。将不胜感激。
首先,要获取所有不在您的数据库中的日期,您需要在最大日期和最小日期之间循环以获取所有日期,并针对每个日期 运行 查询以匹配您想要的过滤器。
使用原始 SQL,首先使用 generate_series
和 lateral join
扩展日期列表,然后进行条件聚合。所以就在这里,有点冗长,但我希望易于阅读。
SQL Fiddle
with t as
(
select is_inner, d::date from the_table
cross join lateral generate_series
(
date_trunc('day', "start"),
date_trunc('day', "end"),
interval '1 day'
) as d
)
select d as event_date,
count(*) filter (where not is_inner) external_events,
count(*) filter (where is_inner) internal_events
from t
group by d order by d;
您也可以像这样使用 jsonb_build_object
塑造问题中的 JSON 结构:
with t as
(
select is_inner, d::date from the_table
cross join lateral generate_series
(
date_trunc('day', "start"),
date_trunc('day', "end"),
interval '1 day'
) as d
)
select jsonb_build_object
(
d::text,
jsonb_build_object('external_events', count(*) filter (where not is_inner),
'internal_events', count(*) filter (where is_inner))
) as date_info
from t
group by d order by d;
date_info
{"2021-12-09": {"external_events": 1, "internal_events": 1}}
{"2021-12-10": {"external_events": 1, "internal_events": 2}}
{"2021-12-11": {"external_events": 0, "internal_events": 1}}
{"2021-12-13": {"external_events": 1, "internal_events": 0}}
{"2021-12-14": {"external_events": 2, "internal_events": 2}}
{"2021-12-15": {"external_events": 2, "internal_events": 2}}
{"2021-12-16": {"external_events": 2, "internal_events": 0}}
我正在使用 Postgresql。我有型号:
class EventsList(CreatedUpdatedMixin):
start = models.DateTimeField()
end = models.DateTimeField()
is_inner = models.BooleanField()
假设我有那些数据库条目:
start | end | is_inner |
---|---|---|
2021-12-09 14:30:12 | 2021-12-09 15:00:21 | true |
2021-12-09 14:00:05 | 2021-12-10 21:00:15 | false |
2021-12-10 09:00:39 | 2021-12-10 09:30:50 | true |
2021-12-10 14:00:00 | 2021-12-11 15:00:00 | true |
2021-12-14 10:00:00 | 2021-12-14 11:00:00 | true |
2021-12-13 13:30:00 | 2021-12-16 14:30:00 | false |
2021-12-14 13:10:00 | 2021-12-15 00:30:00 | true |
2021-12-14 10:30:00 | 2021-12-16 13:34:00 | false |
2021-12-15 13:30:00 | 2021-12-15 18:30:00 | true |
这就是我需要的结果:
[
{"2021-12-09": {"external_events": 1, "internal_events": 1}},
{"2021-12-10": {"external_events": 0, "internal_events": 2}},
{"2021-12-11": {"external_events": 0, "internal_events": 1}},
{"2021-12-13": {"external_events": 1, "internal_events": 0}},
{"2021-12-14": {"external_events": 2, "internal_events": 2}},
{"2021-12-15": {"external_events": 2, "internal_events": 2}},
{"2021-12-16": {"external_events": 2, "internal_events": 0}},
]
所以我想获取所有现有日期,并为每个日期获取外部事件的计数(其中 is_inner == False)和内部事件的计数(其中 is_inner == True ). 我如何使用 Django ORM 或原始 SQL 来完成? 现在,我想出了
EventsList.objects.annotate(
start_day=Cast("start", output_field=DateField())
).values("start_day").annotate(
external_events=Count("id", filter=Q(is_inner=False)),
internal_events=Count("id", filter=Q(is_inner=True)),
).values(
"start_day", "external_events", "internal_events"
)
此代码 returns 几乎是正确的结果(但仅适用于“开始”日期)。我需要包括所有日期(开始日期、结束日期以及它们之间的所有日期)。将不胜感激。
首先,要获取所有不在您的数据库中的日期,您需要在最大日期和最小日期之间循环以获取所有日期,并针对每个日期 运行 查询以匹配您想要的过滤器。
使用原始 SQL,首先使用 generate_series
和 lateral join
扩展日期列表,然后进行条件聚合。所以就在这里,有点冗长,但我希望易于阅读。
SQL Fiddle
with t as
(
select is_inner, d::date from the_table
cross join lateral generate_series
(
date_trunc('day', "start"),
date_trunc('day', "end"),
interval '1 day'
) as d
)
select d as event_date,
count(*) filter (where not is_inner) external_events,
count(*) filter (where is_inner) internal_events
from t
group by d order by d;
您也可以像这样使用 jsonb_build_object
塑造问题中的 JSON 结构:
with t as
(
select is_inner, d::date from the_table
cross join lateral generate_series
(
date_trunc('day', "start"),
date_trunc('day', "end"),
interval '1 day'
) as d
)
select jsonb_build_object
(
d::text,
jsonb_build_object('external_events', count(*) filter (where not is_inner),
'internal_events', count(*) filter (where is_inner))
) as date_info
from t
group by d order by d;
date_info |
---|
{"2021-12-09": {"external_events": 1, "internal_events": 1}} |
{"2021-12-10": {"external_events": 1, "internal_events": 2}} |
{"2021-12-11": {"external_events": 0, "internal_events": 1}} |
{"2021-12-13": {"external_events": 1, "internal_events": 0}} |
{"2021-12-14": {"external_events": 2, "internal_events": 2}} |
{"2021-12-15": {"external_events": 2, "internal_events": 2}} |
{"2021-12-16": {"external_events": 2, "internal_events": 0}} |