Spook Spook - 4 months ago 13
SQL Question

SQLite query for n-th day of month

Say, I have the following table:

CREATE TABLE Data (
Id INTEGER PRIMARY KEY,
Value DECIMAL,
Date DATE);


Since the application is finance-related, user may choose, which day would be the first day of the month. For instance, if he receives salary every 10th of the month, he may set the first day of the month to be 10th.

I'd like to create a query, which returns average value for n-th day of month, as defined by user. For instance:

Date | Value
---------------+------
10.01.2016 | 10
11.01.2016 | 15
10.02.2016 | 20
11.03.2016 | 10


Result of the query should be:

Day | Average
----+--------
1 | 15
2 | 12.5


Note, that if user sets first day to 10th, 9th of the month may be 28th, 29th, 30th or 31st day of a month (depending on which month we're talking about). So this is not as simple as extracting day number from the date.

CL. CL.
Answer

Assuming that the date values do not use the format dd.mm.yyyy but one of the supported date formats, you can use the built-in date functions to compute this.

To compute the difference, in days, between two dates, convert them into a date format that uses days as a number, i.e., Julian days.

To get the 'base' day for a month, we can use modifiers:

> SELECT julianday('2001-02-11') -
         julianday('2001-02-11', 'start of month', '+10 days') + 2;
2.0

(The +2 is needed because we add to the 1st of the month, not the 0th, and we count beginning at 1, not 0.)

If the day is before the tenth, the computed value would become zero or negative, and we have to use the previous month instead:

> SELECT julianday('2001-02-09') -
         julianday('2001-02-09', 'start of month', '-1 month', '+10 days') + 2;
31.0

Combining these results in this expression to compute the n for a date Date:

CASE
WHEN julianday(Date) -
     julianday(Date, 'start of month', '+10 days') + 2 > 0
THEN julianday(Date) -
     julianday(Date, 'start of month', '+10 days') + 2
ELSE julianday(Date) -
     julianday(Date, 'start of month', '-1 month', '+10 days') + 2
END

You can the use this in your query:

SELECT CASE...END AS Day,
       AVG(Value) AS Average
FROM Data
GROUP BY Day;
Comments