Getting records from the past x weeks - sql

I've been fighting with an issue about querying the records where created_at is within the current, or past x weeks. Say, today is Wednesday, so that'd be from Monday at midnight, up to now, if x = 1. If x > 1, I'm looking for current week, up to today, or past week, but not using regular interval '1 week' as that'll get me Wednesday to Wednesday, and I'm only looking into "whole" weeks.
I've tried the interval-solution, and also things like WHERE created_at > (CURRENT_DATE - INTERVAL '5 week').
A solution that'll work for both day, month, year etc, would be preferred, as I'm actually building the query through some other backend logic.
I'm looking for a generic query for "Find everything that's been created 'x periods' back.
Edit:
Since last time, I've implemented this in my Ruby on Rails application. This has caused some problems when using HOUR. The built is working for everything but HOUR (MONTH, DAY, and YEAR)
SELECT "customer_uses".*
FROM "customer_uses"
WHERE (customer_uses.created_at > DATE_TRUNC('MONTH', TIMESTAMP '2017-09-17T16:45:01+02:00') - INTERVAL '1 MONTH')
Which works correctly on my test cases. (Checking count of this). The TIMESTAMP is generated by DateTime.now to ensure my test-cases working with a time-override for "time-travelling"-tests, therefore not using the built in function.
(I've stripped away some extra WHERE-calls which should be irrelevant).
Why the HOUR isn't working is a mystery for me, as I'm using it with a interpolated string for HOUR instead of MONTH as above like so:
SELECT "customer_uses".*
FROM "customer_uses"
WHERE (customer_uses.created_at > DATE_TRUNC('HOUR', TIMESTAMP '2017-09-17T16:45:21+02:00') - INTERVAL '1 HOUR')

Your current suggested query is almost right, except that it uses the current date instead of the start of the week:
SELECT * FROM your_table WHERE created_at > (CURRENT_DATE - INTERVAL '5 week')
Instead, we can check 5 week intervals backwards, but from the start of the current week:
SELECT *
FROM your_table
WHERE created_at > DATE_TRUNC('week', CURRENT_DATE) - INTERVAL '5 week';
I believe you should be able to use the above query as a template for other time periods, e.g. a certain number of months. Just replace the unit in DATE_TRUNC and in the interval of the WHERE clause.

Related

Amazon Athena Date Functions [duplicate]

This question already has answers here:
Presto: Last day of the month prior
(2 answers)
Closed 4 months ago.
I understand Athena uses Presto, however the function last_day_of_month(x) in the documentation doesn't seem to work in AWS Athena.
Is there a function I can use to get the last day of the previous month based on the current date (30 september 2021), last day of previous year (31 december 2021) and last day of the half year (30 June 2022) etc?
I used the below script to do this, however it would be good to know if there's a function I can use or simpler way to run the dates.
SELECT date_trunc('month', current_date) - interval '1' day
SELECT date_trunc('year',(date_trunc('month', current_date) - interval '1' day)) - interval '1' day
SELECT date_add('month',6, date_trunc('year',(date_trunc('month', current_date) - interval '1' day)) - interval '1' day)
First, you need to upgrade your Workgroup to use the Athena engine version 3, which already supports last_day_of_month(x) function.
Athena is based on Presto/Trino, and each version of the Athena engine is based on a different version of the open-source project. You can control the version from the Workgroups menu and even let Athena upgrade the engine automatically for you.
Second, if you want a get the last day of the previous month, the easiest way is to create the first day of the following month and substruct one day from it.
SELECT date '2012-08-01' - interval '1' day
Therefore, if you want the last day of the previous month, and as suggested in the comment, using date_trunc:
SELECT date_trunc('month', current_date ) - interval '1' day
--- half year back
SELECT date_trunc('month', current_date - interval '6' month) - interval '1' day
--- one year back
SELECT date_trunc('month', current_date - interval '1' year) - interval '1' day

PostgreSQL query to return the set of days between two dates

I need to return the dates between the 05 of the last month and the 05 of the current month Example today is the 16/08/2022 I recuperate therefore the whole of the days between the 05/07/2022 and the 05/08/2022
For the moment I try with this query
SELECT DATE from Db_name where date between date_trunc('month', current_date-1) and date_trunc('month',current_date)
Your initial query is very much on track. Just a couple additional things about dates:
current_date-1 subtracts 1 day, you need to subtract 1 month. Thus current_date - interval '1 month'.
date_trunc(somedate) returns the 1st of the month so
date_trunc('2022-08-17') returns 2022-08-01.
getting to the 5th of the month from the 1st just add interval '4 days'.
adding or subtracting intervals to dates results in timestamps.
Since you want dates so needs to be cast back to date.
select *
from db_name
where some_date between (date_trunc('month', current_date-interval '1 month') + interval '4 days')::date
and (date_trunc('month', current_date) + interval '4 days')::date;
But I will repeat do not any reserved word or data type as a name. At best is causes confusion, at worst it will run but do the wrong thing.

postgresql query to return the day of the week of the first day of the month two years from today

I used postgresql to solve the quesion, query to return the day of the week of the first day of the month two years from today. I was able to solve it with the query below, but I am not sure my query is correct, I just wanna make sure
select cast(date_trunc('month', current_date + interval '2 years') as date)
You are correctly computing the first day of the month two years later with:
date_trunc('month', current_date + interval '2 years')
If you want the corresponding day of the week, you can use extract();
extract(dow from date_trunc('month', current_date + interval '2 years'))
This gives you an integer value between 0 (Sunday) and 6 (Saturday)

Get average for "last month" only

Pretty new to SQL and have hit a roadblock.
I have this query, which works fine:
SELECT
(COUNT(*)::float / (current_date - '2017-05-17'::date)) AS "avg_per_day"
FROM "table" tb;
I now want it to include only data from the last month, not all time.
I've tried doing something along the lines of:
SELECT
(COUNT(*)::float / (current_date - (current_date - '1 month' ::date)) AS "avg_per_day"
FROM "table" tb;
The syntax is clearly wrong, but I am not sure what the right answer is. Have googled around and tried various options to no avail.
I can't use a simple AVG because the number I require is an AVG per day for the last month of data. Thus I've done a count of rows divided by the number of days since the first occurrence to get my AVG per day.
I have a column which tells me the date of the occurrence, however there are multiple rows with the same date in the dataset. e.g.
created_at
----------------------------
Monday 27th June 2017 12:00
Monday 27th June 2017 13:00
Tuesday 28th June 2017 12:00
and so on.
I am counting the number of occurrences per day and then need to work out an average from that, for the last month of results only (they date back to May).
The answer depends on the exact definition of "last month" and the exact definition of "average count".
Assuming:
Your column is defined created_at timestamptz NOT NULL
You want the average number of rows per day - days without any rows count as 0.
Cover 30 days exactly, excluding today.
SELECT round(count(*)::numeric / 30, 2) -- simple now with a fixed number of days
FROM tbl
WHERE created_at >= (now()::date - 30)
AND created_at < now()::date -- excl. today
Rounding is optional, but you need numeric instead of float to use round() this way.
Not including the current day ("today"), which is ongoing and may result in a lower, misleading average.
If "last month" is supposed to mean something else, you need to define it exactly. Months have between 28 and 31 days, this can mean various things. And since you obviously operate with timestamp or timestamptz, not date, you also need to be aware of possible implications of the time of day and the current time zone. The cast to date (or the definition of "day" in general) depends on your current timezone setting while operating with timestamptz.
Related:
Ignoring timezones altogether in Rails and PostgreSQL
Select today's (since midnight) timestamps only
Subtract hours from the now() function
I think you just need a where clause:
SELECT
(COUNT(*)::float / (current_date - (current_date - '1 month' ::date)) AS "avg_per_day"
FROM "table" tb
WHERE created_at > (current_date - '1 month' ::date)
I believe Postgresql and other RDBMS has AVG() to calculate average.
SELECT AVG(tb.columnName) AS avg_per_month
FROM someTable tb
WHERE
tb.createdDate >= [start date of month] AND
tb.createdDate <= [end date of month]
Edit: I subtract current date with INTERVAL. I am on mobile phone so I cannot test.
SELECT
(COUNT(*)::float / (current_date - ( current_date - INTERVAL '1 month')) AS "avg_per_day"
FROM "table" tb;

SQL in postgres convert datetime for recurring event to future datetime

I'm keep track of recurring weekly events in a table using just a DATETIME. I only care about the TIME and the day of the week it falls on.
I need to be able to convert the set DATETIME into the current or upcoming future one.
IE How can I convert a date stored as 2013-02-22 12:00:00 using the current date to the next occurrence? Ie this next Friday at 12:00:00 or 2013-03-01 12:00:00 so that I can then order events by date?
Or I could store the TIME and day of the week separately as a number 0-6.
UPDATE:
From Erwin I got something like:
Event.order("date_trunc('week', now()::timestamp) + (start_at - date_trunc('week', start_at))")
Which seems order them except that the first dates I get are Monday skipping over events I know exist for Sunday which it puts as last.
Your best choice is to store a timestamp or timestamptz (timestamop with time zone). If you have or ever will have to deal with more than one time zone, make that timestamptz and define whether you want to operate with local time or UTC or whatever. More details in this related answer:
Ignoring timezones altogether in Rails and PostgreSQL
Demo how to transpose a timestamp into the current week efficiently (same day of week and time). Assuming timestamp here:
SELECT date_trunc('week', now()::timestamp) + (t - date_trunc('week', t))
FROM (SELECT '2013-02-15 12:00:00'::timestamp AS t) x;
The trick is to compute the interval between the start of the corresponding week and the given timestamp and add that to the start of the current week with the help of date_trunc().
The ISO week starts with Monday, putting Sunday last.
Or, to just add a week to a given timestamp:
SELECT t + interval '1 week';
If You just want to ORDER BY, you only need the interval:
ORDER BY (t - date_trunc('week', t))
If you want to put Sunday first (shifting days):
ORDER BY ((t + interval '1d') - date_trunc('week', (t + interval '1d'))
Or simpler:
ORDER BY EXTRACT(dow FROM t), t::time
Quoting the manual on EXTRACT():
dow
The day of the week as Sunday(0) to Saturday(6)
isodow
The day of the week as Monday(1) to Sunday(7)
Answer to question in comment
I'm only interested in ordering them relative to the current date. Ie
if it's tuesday, I want tuesday first, monday last.
Wrapping at midnight of "today":
ORDER BY (EXTRACT(dow FROM t)::int + 7 - EXTRACT(dow FROM now())::int) % 7
,t::time
Using the modulo operator % to shift the day according to "today".
Using dowinstead of isodow, because starting with 0 makes % simpler.
Keep using the datetime. It's simple and gives you flexibility. You can use the extract function to get your time of day and day of week results. This page will help you. http://www.postgresql.org/docs/9.3/static/functions-datetime.html