Last 14 days vs before last 14 days data - sql

orders
id
order_id
created_at
updated_at
total_amount
1
abc123
2021-06-13 11:00:00
2021-06-13 11:00:00
230.5
2
abc456
2021-06-01 07:00:00
2021-06-01 07:00:00
240
To get no of purchases on last 7 days vs before last 7 days I wrote the following query
select
date_trunc('week', created_at) as "Week",
count(*) "No of purchases"
from orders
How can I get no of purchases on last 14 days vs before last 14 days?
Is there a way I can pass like '14 days' or something like that to date_turnc method?
If not How Can I write this query?

Why not just use date comparisons?
select count(*) as num_purchases
from orders
where created_at >= current_date - interval '14 day'

Just subtract the respective intervals from now() (or any other function/variable that gives you the right time for the current moment) and compare that to the creation timestamp. Something along the lines of:
SELECT count(*)
FROM orders
WHERE created_at >= now() - '14 days'::interval
AND created_at < now() - '7 days'::interval;

Related

Issue with Date_SUB And BETWEEN function

I came across this issue while creating a parametrised query; Then intent of the query is to pull past 5 months (excluding current month) data based on the date passed as a variable. Basic table schema for Table A is as follows:
as_of_date Y X
2019-12-31 1 AB
2019-11-30 2 CD
2019-10-31 3 EF
2019-09-30 4 GH
2019-08-31 5 MN
2019-07-31 6 XYZ
2020-01-31 7 PQR
2020-02-29 8 AAA
Following is the query I wrote:
WITH
date
AS
(
SELECT CAST("2020-02-29" AS Date) as run_date
)
SELECT DISTINCT CAST(a.as_of_date AS DATE) as_of_date,
FROM A as a
WHERE CAST(a.as_of_date AS DATE) BETWEEN DATE_SUB((SELECT run_date FROM date), INTERVAL 5 Month) AND DATE_SUB((SELECT run_date FROM date), INTERVAL 1 Month)
This query runs fine when run_date is set to "2020-01-31" and returns past 5 months data i.e. Dec, Nov, October, Sept, and August. But fails when date is set to "2020-02-29" it only returns 4 months data.
Simple "fix" is to add DATE_TRUNC(..., MONTH) as in below example
SELECT DISTINCT CAST(a.as_of_date AS DATE) as_of_date,
FROM `project.dataset.tableA` AS a
WHERE DATE_TRUNC(CAST(a.as_of_date AS DATE), MONTH)
BETWEEN DATE_TRUNC(DATE_SUB((SELECT run_date FROM date_cte), INTERVAL 5 Month), MONTH)
AND DATE_TRUNC(DATE_SUB((SELECT run_date FROM date_cte), INTERVAL 1 Month), MONTH)

How to combine two different counts from two different date ranges sql

I'll try to keep this simple.
I have two queries that work just fine, they both count how many users signed up that day between a specific date range.
Query 1 - gets a list of users that signed up for each day a year from today. Here is a picture of the outcome.
SELECT users.created::date,
count(users.id)
FROM users
WHERE users.created::date < now() - interval '12 month'
AND users.created::date > now() - interval '13 month'
AND users.thirdpartyid = 100
GROUP BY users.created::date
ORDER BY users.created::date
Query 2 - gets a list of users that signed up for each day a month ago from today. Here is a picture of this outcome.
SELECT users.created::date,
count(users.id)
FROM users
WHERE users.created::date > now() - interval '1 month'
AND users.thirdpartyid = 100
GROUP BY users.created::date
ORDER BY users.created::date
What I'm stuck on is how can I combine these two queries so that I could create a stack bar graph on my redash website. They are obviously both different years but I'd like my X axis to be the day of the month and the Y to be the number of users. Thank you.
Edit:
Here is an example output that I think would work perfectly for me.
| Day of the month | Users signed up December 2017 | Users signed up December 2018
|------------------ | ----------------------------- | -----------------------------|
| 01 45 56
| ----------------- | ---------------------------- | -----------------------------|
| 02 47 32
| ----------------- | ---------------------------- | -----------------------------|
etc...
You could try using filters. I took the liberty to select the day of month as you seem to want that rather than the full date.
SELECT date_part('day', users.created::date) as day_of_month,
count(users.id) FILTER (
WHERE users.created::date < now() - interval '12 month'
AND users.created::date > now() - interval '13 month') AS month_12,
count(users.id) FILTER (
WHERE users.created::date > now() - interval '1 month') AS month_1
FROM users
WHERE (
(
users.created::date < now() - interval '12 month'
AND users.created::date > now() - interval '13 month'
) OR users.created::date > now() - interval '1 month'
)
AND users.thirdpartyid = 100
GROUP BY day_of_month
ORDER BY day_of_month

How do I compare a current partial month vs a previous partial month with postgres?

I'm building some basic reports and I want to see if I'm on track to surpass last month's metrics without waiting for the month to end. Basically I want to compare June 1 (start of current month) through June 23 (current_date) against May 1 (start of previous month) through May 23 (current_date - 1 month).
My goal is to show a count of distinct users that did event1 and event2.
Here's what I have so far:
CREATE VIEW events AS
(SELECT *
FROM public.event
WHERE TYPE in ('event1',
'event2')
AND created_at > now() - interval '1 months' );
CREATE VIEW MAU AS
(SELECT EXTRACT(DOW
FROM created_at) AS month,
DATE_TRUNC('week', created_at) AS week,
COUNT(*) AS total_engagement,
COUNT(DISTINCT user_id) AS total_users
FROM events
GROUP BY 2,
1
ORDER BY week DESC);
SELECT month,
week,
SUM(total_engagement) OVER (PARTITION BY month
ORDER BY week) AS total_engagment
FROM MAU
ORDER BY 1 DESC,
2
Here's an example of what that returns:
Month Week Unique Engagement
6 2017-05-22 00:00:00 165
6 2017-05-29 00:00:00 355
6 2017-06-05 00:00:00 572
6 2017-06-12 00:00:00 723
5 2017-05-22 00:00:00 757
5 2017-05-29 00:00:00 1549
5 2017-06-05 00:00:00 2394
5 2017-06-12 00:00:00 3261
5 2017-06-19 00:00:00 3592
Expected return
Month Day Total Engagement
6 1 50
6 2 100
6 3 180
5 1 89
5 2 213
5 3 284
5 4 341
Can you point out where I've got this wrong or if there's an easier way to do it?
You are confusing days, weeks and months in your question but from the expected output I assume that you want month number, week number within a month and a count of those pairs.
SELECT
month,
week,
count(*) as total_engagement
FROM (
SELECT
extract(month from created_at) as month,
extract('day' from date_trunc('week', created_at::date) -
date_trunc('week', date_trunc('month', created_at::date))) / 7 + 1 as week
FROM public.event
WHERE type IN ('event1', 'event2')
AND created_at > now() - interval '1 month'
) t
GROUP BY 1,2
The most interesting part could be getting the week number within a month and for that you can check this answer.

Get the highest value of the last 7 days with SQL

I would like to fetch the highest value (from the column named value) for the 7 past days. I have tried with this sql:
SELECT MAX(value) as value_of_week
FROM events
WHERE event_date > UNIX_TIMESTAMP() -(7 * 86400);
But it gives me 86.1 that is older than 7 days from today´s date. Given the rows below, I should get 55.2 with date 2014-05-16 07:07:00.
id value event_date
1 28. 2014-04-18 08:23:00
2 23.6 2014-04-22 06:43:00
3 86.1 2014-04-29 05:32:00
4 43.3 2014-05-03 08:12:00
5 55.2 2014-05-16 07:07:00
6 25.6 2014-05-19 06:11:00
You are comparing unix time stamps to date. How about this?
SELECT MAX(value) as value_of_week
FROM events
WHERE event_date > date_add(now(), interval -7 day);
Im guessing this is MySQL and in that case you could do this:
select max(value) as value_of_week from events where event_date between date_sub(now(),INTERVAL 1 WEEK) and now();
you can use
SELECT MAX(value) as value_of_week
FROM events
where event_date>= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY
AND event_date< curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY;

Postgres group by timestamp into 6 hourly buckets

I have the following simple table:
ID TIMESTAMP VALUE
4 2011-05-27 15:50:04 1253
5 2011-05-27 15:55:02 1304
6 2011-05-27 16:00:02 1322
7 2011-05-27 16:05:01 1364
I would like to average the VALUES, and GROUP each TIMESTAMP day into 6 hourly buckets. e.g 00:00 to 06:00, 06:00 to 12:00, 12:00 to 18:00 & 18:00 to 00:00.
I am able to group by year, month, day & hour using the following query:
select avg(VALUE),
EXTRACT(year from TIMESTAMP) AS year,
EXTRACT(month from TIMESTAMP) AS month,
EXTRACT(day from TIMESTAMP) as day
from TABLE
group by year,month,day
But I am unable to group each day into 4 periods as defined above, any help is most welcome.
I think grouping the integer value of the quotient of the (Hour of your timestamp / 6) should help. Try it and see if it helps.
Your group by should be something like
group by year, month, day, trunc(EXTRACT(hour from TIMESTAMP) / 6)
The logic behind this is that when the hour part of the date is divided by 6, the int values can only be
0 - 0:00 - 5:59:59
1 - 6:00 - 11:59:59
2 - 12:00 - 17:59:59
3 - 18:00 - 23:59:59
Grouping using this should put your data into 4 groups per day, which is what you need.