Delphi & SQLite: 获取过去 12 个月每月的记录数

Delphi & SQLite: Get the records count per month for the last 12 months

我正在尝试获取过去 12 个月(包括当前月份)按月分组的记录数。 不是当年年初。

我有一个 table 事件和一个字段 WODATE。我可以做到

  aFDQuery.Connection := TrackingDBConnection;
  aFDQuery.SQL.Clear;
  with aFDQuery.SQL do
    begin
      BeginUpdate;
      try
        Add('Select MONTH(MAX(WODate)) AS month, COUNT(*) AS count ');
        Add('from events where YEAR(WODATE) = 2020 ');
        Add('GROUP BY YEAR(WODate), MONTH(WODate) ORDER BY YEAR(WODate), MONTH(WODate) ASC');
      finally
        EndUpdate;
      end;

通过该查询,我只得到了除 0 以外的值的几个月的结果,而且显然只得到了 2020 年的结果

但我想从现在开始的最后 12 个月,即使是这样的 0

[01]    11/2019     12 
[02]    12/2019     24 
[03]    01/2020      0 
[04]    02/2020     12
[05]    03/2020     44
[06]    04/2020      0
[07]    05/2020     21
[08]    06/2020     37
[09]    07/2020      0
[10]    08/2020     15 
[11]    09/2020     45 
[12]    10/2020      6

我试过了,但出现语法错误

Add('from EVENTS where WODATE >= DATE(NOW, -12 month) ');

ESQLiteNativeException: [FireDAC][Phys][SQLite] ERROR: near "month": syntax error

可能吗?预先感谢您的任何建议

有了 Peter 的回答(见下文),我明白了

2019-11-01 - 2019-11-30    0
2019-12-01 - 2019-12-31    0
2020-01-01 - 2020-01-31    0
2020-02-01 - 2020-02-29    0
2020-03-01 - 2020-03-31    0
2020-04-01 - 2020-04-30    0
2020-05-01 - 2020-05-31    0
2020-06-01 - 2020-06-30    0
2020-07-01 - 2020-07-31    0
2020-08-01 - 2020-08-31    0
2020-09-01 - 2020-09-30    0
2020-10-01 - 2020-10-31   13

这是完美的 非常感谢彼得。你值得拥有比利时啤酒

这不是一个 Delphi 问题,而是 SQL 一个简单的问题。自 version 3.8.3 you can use common table expressions (CTE) and the VALUES clause。下面我来解释一下。

首先,您可以构建包含 12 个条目的静态日期范围 table,其中每个条目代表过去 12 个月中的一个月,包括当前:

VALUES
  (date('now', 'start of month', '-11 month'), date('now', 'start of month', '-10 month', '-1 day')),
  (date('now', 'start of month', '-10 month'), date('now', 'start of month', '-9 month', '-1 day')),
  (date('now', 'start of month', '-9 month'),  date('now', 'start of month', '-8 month', '-1 day')),
  (date('now', 'start of month', '-8 month'),  date('now', 'start of month', '-7 month', '-1 day')),
  (date('now', 'start of month', '-7 month'),  date('now', 'start of month', '-6 month', '-1 day')),
  (date('now', 'start of month', '-6 month'),  date('now', 'start of month', '-5 month', '-1 day')),
  (date('now', 'start of month', '-5 month'),  date('now', 'start of month', '-4 month', '-1 day')),
  (date('now', 'start of month', '-4 month'),  date('now', 'start of month', '-3 month', '-1 day')),
  (date('now', 'start of month', '-3 month'),  date('now', 'start of month', '-2 month', '-1 day')),
  (date('now', 'start of month', '-2 month'),  date('now', 'start of month', '-1 month', '-1 day')),
  (date('now', 'start of month', '-1 month'),  date('now', 'start of month', '-1 day')),
  (date('now', 'start of month'),              date('now', 'start of month', '+1 month', '-1 day'))

这给出(截至当前日期):

StartDate EndDate
2019-11-01 2019-11-30
2019-12-01 2019-12-31
2020-01-01 2020-01-31
2020-02-01 2020-02-29
2020-03-01 2020-03-31
2020-04-01 2020-04-30
2020-05-01 2020-05-31
2020-06-01 2020-06-30
2020-07-01 2020-07-31
2020-08-01 2020-08-31
2020-09-01 2020-09-30
2020-10-01 2020-10-31

使用 CTE,您可以将您的 events table 加入到上面的列表中:

WITH DateRanges(StartDate, EndDate) AS (VALUES
  (date('now', 'start of month', '-11 month'), date('now', 'start of month', '-10 month', '-1 day')),
  (date('now', 'start of month', '-10 month'), date('now', 'start of month', '-9 month', '-1 day')),
  (date('now', 'start of month', '-9 month'),  date('now', 'start of month', '-8 month', '-1 day')),
  (date('now', 'start of month', '-8 month'),  date('now', 'start of month', '-7 month', '-1 day')),
  (date('now', 'start of month', '-7 month'),  date('now', 'start of month', '-6 month', '-1 day')),
  (date('now', 'start of month', '-6 month'),  date('now', 'start of month', '-5 month', '-1 day')),
  (date('now', 'start of month', '-5 month'),  date('now', 'start of month', '-4 month', '-1 day')),
  (date('now', 'start of month', '-4 month'),  date('now', 'start of month', '-3 month', '-1 day')),
  (date('now', 'start of month', '-3 month'),  date('now', 'start of month', '-2 month', '-1 day')),
  (date('now', 'start of month', '-2 month'),  date('now', 'start of month', '-1 month', '-1 day')),
  (date('now', 'start of month', '-1 month'),  date('now', 'start of month', '-1 day')),
  (date('now', 'start of month'),              date('now', 'start of month', '+1 month', '-1 day'))
)
SELECT
  DateRanges.StartDate,
  DateRanges.EndDate,
  COUNT(Events.ROWID) AS Count
FROM DateRanges
  LEFT OUTER JOIN Events ON (DateRanges.StartDate <= Events.WODate) AND (Events.WODate <= DateRanges.EndDate)
GROUP BY
  DateRanges.StartDate, DateRanges.EndDate
ORDER BY
  DateRanges.StartDate

sample SQLFiddle

编辑

我看到您正在努力使用 TFDQuery 执行 SQL,所以我为您做了:

with aFDQuery.SQL do
begin
  BeginUpdate;
  try
    Add('WITH DateRanges(StartDate, EndDate) AS (VALUES');
    Add('(date(''now'', ''start of month'', ''-11 month''), date(''now'', ''start of month'', ''-10 month'', ''-1 day'')),');
    Add('(date(''now'', ''start of month'', ''-10 month''), date(''now'', ''start of month'', ''-9 month'', ''-1 day'')),');
    Add('(date(''now'', ''start of month'', ''-9 month''),  date(''now'', ''start of month'', ''-8 month'', ''-1 day'')),');
    Add('(date(''now'', ''start of month'', ''-8 month''),  date(''now'', ''start of month'', ''-7 month'', ''-1 day'')),');
    Add('(date(''now'', ''start of month'', ''-7 month''),  date(''now'', ''start of month'', ''-6 month'', ''-1 day'')),');
    Add('(date(''now'', ''start of month'', ''-6 month''),  date(''now'', ''start of month'', ''-5 month'', ''-1 day'')),');
    Add('(date(''now'', ''start of month'', ''-5 month''),  date(''now'', ''start of month'', ''-4 month'', ''-1 day'')),');
    Add('(date(''now'', ''start of month'', ''-4 month''),  date(''now'', ''start of month'', ''-3 month'', ''-1 day'')),');
    Add('(date(''now'', ''start of month'', ''-3 month''),  date(''now'', ''start of month'', ''-2 month'', ''-1 day'')),');
    Add('(date(''now'', ''start of month'', ''-2 month''),  date(''now'', ''start of month'', ''-1 month'', ''-1 day'')),');
    Add('(date(''now'', ''start of month'', ''-1 month''),  date(''now'', ''start of month'', ''-1 day'')),');
    Add('(date(''now'', ''start of month''),              date(''now'', ''start of month'', ''+1 month'', ''-1 day'')))');
    Add('SELECT DateRanges.StartDate, DateRanges.EndDate, COUNT(Events.ROWID) AS Count');
    Add('FROM DateRanges LEFT OUTER JOIN Events ON (DateRanges.StartDate <= Events.WODate) AND (Events.WODate <= DateRanges.EndDate)');
    Add('GROUP BY DateRanges.StartDate, DateRanges.EndDate');
    Add('ORDER BY DateRanges.StartDate');
  finally
    EndUpdate;
  end;
end;

用户 Peter Wolf 回答我设计了这个小修改回答 - IMO - 更好的问题:

WITH DateRanges(StartDate, EndDate) AS (VALUES
  (date('now', 'start of month', '-11 month'), date('now', 'start of month', '-10 month', '-1 day')),
  (date('now', 'start of month', '-10 month'), date('now', 'start of month', '-9 month', '-1 day')),
  (date('now', 'start of month', '-9 month'),  date('now', 'start of month', '-8 month', '-1 day')),
  (date('now', 'start of month', '-8 month'),  date('now', 'start of month', '-7 month', '-1 day')),
  (date('now', 'start of month', '-7 month'),  date('now', 'start of month', '-6 month', '-1 day')),
  (date('now', 'start of month', '-6 month'),  date('now', 'start of month', '-5 month', '-1 day')),
  (date('now', 'start of month', '-5 month'),  date('now', 'start of month', '-4 month', '-1 day')),
  (date('now', 'start of month', '-4 month'),  date('now', 'start of month', '-3 month', '-1 day')),
  (date('now', 'start of month', '-3 month'),  date('now', 'start of month', '-2 month', '-1 day')),
  (date('now', 'start of month', '-2 month'),  date('now', 'start of month', '-1 month', '-1 day')),
  (date('now', 'start of month', '-1 month'),  date('now', 'start of month', '-1 day')),
  (date('now', 'start of month'),              date('now', 'start of month', '+1 month', '-1 day'))
)
SELECT
  strftime('%m/%Y', DateRanges.StartDate) as Month,
  COUNT(Events.ROWID) AS Count
FROM DateRanges
  LEFT OUTER JOIN Events ON (DateRanges.StartDate <= Date(Events.WODate)) AND (Events.WODate <= Date(DateRanges.EndDate))
GROUP BY
  DateRanges.StartDate, DateRanges.EndDate
ORDER BY
  DateRanges.StartDate