如何在 Postgres 中获取过去 12 周的发票数量
How to get number of invoices for last 12 weeks in Postgres
发票数据库包含发票日期:
create table dok (
dokumnr serial primary key,
invoicedate date not null
);
仪表板需要包含过去 12 周发票数量的逗号分隔列表,e.q
4,8,0,6,7,6,0,6,0,4,5,6
列表始终包含 12 个元素。如果在 7 天的时间间隔内没有发票,则应显示 0。
每个元素应包含 7 天的发票数量。
查询应该找到当前日期之前的最大日期:
select max(invoicedate) as last_date from dok;
然后可能使用 count(*) 和 string_agg() 来创建列表。
最后(第 12 个)元素应包含
的发票数量
last_date .. last_date-interval'6days'
11 个元素(前一个)应包含几天的发票数量
last_date-interval'7days' .. last_date-interval'14days'
等等
如何在 Postgres 9.1+ 中编写此查询?
这是 ASP.NET MVC3 C# 应用程序,如果有帮助,部分查询也可以用 C# 代码完成。
我结束于
with list as (
SELECT count(d.invoicedate) as cnt
FROM (
SELECT max(invoicedate) AS last_date
FROM dok
WHERE invoicedate< current_date
) l
CROSS JOIN generate_series(0, 11*7, 7) AS g(days)
LEFT JOIN dok d ON d.invoicedate> l.last_date - g.days - 7
AND d.invoicedate<= l.last_date - g.days
GROUP BY g.days
ORDER BY g.days desc
)
SELECT string_agg( cnt::text,',')
from list
CROSS JOIN
最晚日期到 generate_series()
,然后 LEFT JOIN
到主要 table。
SELECT ARRAY(
SELECT count(d.invoicedate) AS ct
FROM (
SELECT max(invoicedate) AS last_date
FROM dok
WHERE invoicedate < current_date -- "maximum date before current date"
) l
CROSS JOIN generate_series(0, 11*7, 7) AS g(days)
LEFT JOIN dok d ON d.invoicedate > l.last_date - g.days - 7
AND d.invoicedate <= l.last_date - g.days
GROUP BY g.days
ORDER BY g.days
);
假设 table 中至少有一个有效条目,
这个 returns 一个 bigint (bigint[]
) 数组,最近一周 first.
current_date
取决于您会话的 timezone
设置。
如果您需要结果是逗号分隔的字符串,您可以使用另一个带有 string_agg()
的查询层。或者您将以上内容提供给 array_to_string()
:
SELECT array_to_string(ARRAY(SELECT ...), ',');
您的查询已审核:
这是一个实现细节,but it's documented:
The aggregate functions array_agg
, json_agg
, jsonb_agg
,
json_object_agg
, jsonb_object_agg
, string_agg
, and xmlagg
, as
well as similar user-defined aggregate functions, produce meaningfully
different result values depending on the order of the input values.
This ordering is unspecified by default, but can be controlled by
writing an ORDER BY
clause within the aggregate call, as shown in
Section 4.2.7. Alternatively, supplying the input values from a
sorted subquery will usually work. For example:
SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;
Beware that this approach can fail if the outer query level contains
additional processing, such as a join, because that might cause the
subquery's output to be reordered before the aggregate is computed.
大胆强调我的。
为了保持标准合规性,您可以这样写:
WITH list AS (
SELECT <b>g.days,</b> count(d.invoicedate)::text AS cnt
FROM (
SELECT max(invoicedate) AS last_date
FROM dok
WHERE invoicedate < current_date
) l
CROSS JOIN generate_series(0, 11*7, 7) AS g(days)
LEFT JOIN dok d ON d.invoicedate > l.last_date - g.days - 7
AND d.invoicedate <= l.last_date - g.days
GROUP BY 1
)
SELECT string_agg(cnt, ',' <b>ORDER BY days DESC</b>)
FROM list;
但这有点慢。此外,CTE 在技术上不是必需的,而且比子查询慢一点。
SELECT array_to_string(ARRAY( SELECT ...), ',')
就像我建议的那样是最快的,因为数组构造函数对于单个结果比聚合函数更快 string_agg()
.
发票数据库包含发票日期:
create table dok (
dokumnr serial primary key,
invoicedate date not null
);
仪表板需要包含过去 12 周发票数量的逗号分隔列表,e.q
4,8,0,6,7,6,0,6,0,4,5,6
列表始终包含 12 个元素。如果在 7 天的时间间隔内没有发票,则应显示 0。 每个元素应包含 7 天的发票数量。
查询应该找到当前日期之前的最大日期:
select max(invoicedate) as last_date from dok;
然后可能使用 count(*) 和 string_agg() 来创建列表。
最后(第 12 个)元素应包含
的发票数量 last_date .. last_date-interval'6days'
11 个元素(前一个)应包含几天的发票数量
last_date-interval'7days' .. last_date-interval'14days'
等等
如何在 Postgres 9.1+ 中编写此查询? 这是 ASP.NET MVC3 C# 应用程序,如果有帮助,部分查询也可以用 C# 代码完成。
我结束于
with list as (
SELECT count(d.invoicedate) as cnt
FROM (
SELECT max(invoicedate) AS last_date
FROM dok
WHERE invoicedate< current_date
) l
CROSS JOIN generate_series(0, 11*7, 7) AS g(days)
LEFT JOIN dok d ON d.invoicedate> l.last_date - g.days - 7
AND d.invoicedate<= l.last_date - g.days
GROUP BY g.days
ORDER BY g.days desc
)
SELECT string_agg( cnt::text,',')
from list
CROSS JOIN
最晚日期到 generate_series()
,然后 LEFT JOIN
到主要 table。
SELECT ARRAY(
SELECT count(d.invoicedate) AS ct
FROM (
SELECT max(invoicedate) AS last_date
FROM dok
WHERE invoicedate < current_date -- "maximum date before current date"
) l
CROSS JOIN generate_series(0, 11*7, 7) AS g(days)
LEFT JOIN dok d ON d.invoicedate > l.last_date - g.days - 7
AND d.invoicedate <= l.last_date - g.days
GROUP BY g.days
ORDER BY g.days
);
假设 table 中至少有一个有效条目,
这个 returns 一个 bigint (bigint[]
) 数组,最近一周 first.
current_date
取决于您会话的 timezone
设置。
如果您需要结果是逗号分隔的字符串,您可以使用另一个带有 string_agg()
的查询层。或者您将以上内容提供给 array_to_string()
:
SELECT array_to_string(ARRAY(SELECT ...), ',');
您的查询已审核:
这是一个实现细节,but it's documented:
The aggregate functions
array_agg
,json_agg
,jsonb_agg
,json_object_agg
,jsonb_object_agg
,string_agg
, andxmlagg
, as well as similar user-defined aggregate functions, produce meaningfully different result values depending on the order of the input values. This ordering is unspecified by default, but can be controlled by writing anORDER BY
clause within the aggregate call, as shown in Section 4.2.7. Alternatively, supplying the input values from a sorted subquery will usually work. For example:SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;
Beware that this approach can fail if the outer query level contains additional processing, such as a join, because that might cause the subquery's output to be reordered before the aggregate is computed.
大胆强调我的。
为了保持标准合规性,您可以这样写:
WITH list AS (
SELECT <b>g.days,</b> count(d.invoicedate)::text AS cnt
FROM (
SELECT max(invoicedate) AS last_date
FROM dok
WHERE invoicedate < current_date
) l
CROSS JOIN generate_series(0, 11*7, 7) AS g(days)
LEFT JOIN dok d ON d.invoicedate > l.last_date - g.days - 7
AND d.invoicedate <= l.last_date - g.days
GROUP BY 1
)
SELECT string_agg(cnt, ',' <b>ORDER BY days DESC</b>)
FROM list;
但这有点慢。此外,CTE 在技术上不是必需的,而且比子查询慢一点。
SELECT array_to_string(ARRAY( SELECT ...), ',')
就像我建议的那样是最快的,因为数组构造函数对于单个结果比聚合函数更快 string_agg()
.