1

发票数据库包含发票日期:

create table dok (
  dokumnr serial primary key,
  invoicedate date not null
);

仪表板需要逗号分隔的列表,其中包含过去 12 周的发票数量,eq

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
4

1 回答 1

1

CROSS JOIN最晚日期 to generate_series(),后跟 aLEFT 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[]其中包含最近的一周first

current_date取决于timezone您的会话设置。

如果您需要结果是逗号分隔的字符串,您可以使用另一个查询层来string_agg()代替。或者您将上述内容提供给array_to_string()

SELECT array_to_string(ARRAY(SELECT ...), ',');

您的查询已审核:

这是一个实现细节,但已记录在案:

聚合函数array_aggjson_aggjsonb_aggjson_object_aggjsonb_object_aggstring_aggxmlagg以及类似的用户定义聚合函数根据输入值的顺序产生有意义的不同结果值。默认情况下未指定此顺序,但可以通过ORDER BY在聚合调用中编写子句来控制,如 第 4.2.7 节所示。或者,从排序的子查询中提供输入值通常会起作用。例如:

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()

于 2015-06-17T22:14:36.220 回答