发票数据库包含发票日期:
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
答案 0 :(得分:1)
CROSS JOIN
generate_series()
的最新日期,然后是主表的LEFT JOIN
。
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
);
假设表格中至少有一个有效条目,
这将返回一个bigint数组(bigint[]
),其中包含最新的第一周。
current_date
取决于您会话的timezone
设置。
如果您需要将结果设置为以逗号分隔的字符串,则可以使用另一个string_agg()
的查询图层。或者您将以上内容提供给array_to_string()
:
SELECT array_to_string(ARRAY(SELECT ...), ',');
这是一个实施细节,but it's documented:
汇总函数
array_agg
,json_agg
,jsonb_agg
,json_object_agg
,jsonb_object_agg
,string_agg
和xmlagg
以及类似的用户定义的聚合函数,产生有意义的 不同的结果值取决于输入值的顺序。 默认情况下,此排序未指定,但可以通过控制 在聚合调用中编写ORDER BY
子句,如图所示 Section 4.2.7。 或者,从a提供输入值 排序的子查询通常会起作用。例如:SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;
请注意,如果外部查询级别包含,则此方法可能会失败 附加处理,例如连接,因为这可能会导致 子查询的输出在计算聚合之前要重新排序。
大胆强调我的 为了保持标准,你可以写:
WITH list AS (
SELECT g.days, 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, ',' ORDER BY days DESC)
FROM list;
但这有点慢。此外,CTE 在技术上不是必需的,也比子查询慢一点
像我提出的SELECT array_to_string(ARRAY( SELECT ...), ',')
是最快的,因为数组构造函数对于单个结果比聚合函数string_agg()
更快。