This isn't much a Delphi question but rather SQLite question. Since version 3.8.3 you can use common table expressions (CTE) and the VALUES
clause. Below I'm going to explain how.
First you can construct static date ranges table with 12 entries, where each entry represents a single month from past 12 months including the current:
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'))
This gives (as of current date):
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 |
Using a CTE you can join your events
table to the above list:
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
See sample SQLFiddle.
Edit
I see that you're struggling to execute the SQL using TFDQuery
, so I did it for you:
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;