Count of Daily Users in PostgreSQL - postgresql

I have a database that looks like this
users
phone created
8001234578 1540231160
9001234578 1540220360
1001234578 1540144760
2001234578 1540058360
Note that the created column is a unix timestamp.
I want to group them by users created on the same day with a count of users, so the above example database should return something like this.
[
{day: '10/22/2018', count: 2},
{day: '10/21/2018', count: 1},
{day: '10/20/2018', count: 1},
]
I tried learning about the to_char command but I couldn't figure it out, this is what I tried:
SELECT
to_char(created, 'Day') as day,
COUNT(*) as count
FROM users
WHERE created >= ${startDate} AND created <= ${endDate}
GROUP BY to_char(created, 'Day')
It returned this:
[{day: ' .ay', count: '4'}]

First, if it's within your control, you should consider using Postgres's built in TIMESTAMP data type, instead of storing your dates as UNIX timestamps. This will make your queries much easier.
That being said, if you're stuck with using UNIX timestamps (presumably stored as integers), you'll have to convert them to a TIMESTAMP anyways to get what you want. You can use the TO_TIMESTAMP to convert from the UNIX timestamp, and use the DATE_TRUNC function to just get the date portion:
SELECT
DATE_TRUNC('day', TO_TIMESTAMP(created)),
COUNT(*)
FROM users
GROUP BY DATE_TRUNC('day', TO_TIMESTAMP(created))
Of course, if you're storing the dates as a Postgres TIMESTAMP, it's the same query, but simpler:
SELECT
DATE_TRUNC('day', created),
COUNT(*)
FROM users
GROUP BY DATE_TRUNC('day', created)

SELECT date_trunc('day', users.created) "day", count(*) as count
FROM users
WHERE created >= ${startDate} AND created <= ${endDate}
GROUP BY 1

You can set datetime format, so you got result like this
postgres# select to_char(now(), 'DD Mon YYYY');
to_char
-------------
22 Oct 2018
(1 row)
In your case query will be like this
SELECT
to_char(created, 'DD Mon YYYY') as day,
COUNT(*) as count
FROM users
WHERE created >= ${startDate} AND created <= ${endDate}
GROUP BY to_char(created, 'DD Mon YYYY')
Here you can find datetime format specification https://www.postgresql.org/docs/9.6/static/functions-formatting.html#FUNCTIONS-FORMATTING-DATETIME-TABLE

Related

how to get hour, month from timestamp in postgresql

timestamp with timezone is this - 2020-05-31T10:05:07Z
this is not working, despite referencing official documentation. I need to extract may 2020 or separate month and year to compare against May 2020
SELECT date_trunc('hour', TIMESTAMP '2020-05-31T10:05:07Z')
SELECT date_part('day', TIMESTAMP '2020-05-31T10:05:07Z');
If you want to check if a timestamp value is "may 2020", you have different options.
to_char(the_value, 'yyyy-mm') = '2020-05'
or
extract(month from the_value) = 5
and extract(year from the_value) = 2020
or
(extract(month from the_value), extract(year from the_value)) = (5, 2020)
extract() and date_part() are the same thing - but I prefer the standard compliant extract() version.
demo:db<>fiddle
You need to_char() to format a date or timestamp. Mon gives you the first three letters of a month name:
SELECT
to_char(
TIMESTAMP '2020-05-31T10:05:07Z',
'Mon YYYY'
)
Returning the entire month name you can use Month instead of Mon. But, for some reasons, the length of the Month value is fixed to the longest month name available. That means May is returned with right padded spaces. To avoid this, you need to add the modifier FM:
SELECT
to_char(
TIMESTAMP '2020-05-31T10:05:07Z',
'FMMonth YYYY'
)

How to find Last Week entries and This Week entries from postgres tables

I want to find the LastWeek entries from postgres table with cycle from Monday to Sunday (both inclusive) For eg - if I query the data today i.e on 2020/07/26 (or say if i query data on any date between 2020/07/20 to 2020/07/26) i should get the data from 2020/07/13 to 2020/07/19
Query:
Select user, date_sent
from users
where date_sent between (SELECT current_date - cast(extract(dow from current_date) as int) - 6)
and (SELECT current_date - cast(extract(dow from current_date) as int) + 1)
Similarly I want to find the This Week entries week starting from Monday and ending on present date. For eg - If I query the data today i.e on 2020/07/26 I should get the data from 2020/07/20 to 2020/07/26. If i query on 2020/07/24 then I should get 2020/07/20 to 2020/07/24
Query:
select user, date_sent
from users
where date_sent >= date_trunc('week', current_date)
and date_sent <= date_trunc('day',current_date+1)
You are almost there.
For "this week":
select user, date_sent
from users
where date_sent >= date_trunc('week', current_date)
and date_sent < date_trunc('week', current_date) + interval '1 week';
For last week it's quite similar:
select user, date_sent
from users
where date_sent >= date_trunc('week', current_date) - interval '1 week'
and date_sent < date_trunc('week', current_date)
Your desired results are inconsistent. In your description, before your initial query you state:
if I query the data today i.e on 2020/07/26 (or say if i query data on
any date between 2020/07/20 to 2020/07/26) i should get the data from
2020/07/13 to 2020/07/19
But after that query you state:
If I query the data today i.e on 2020/07/26 I should get the data from
2020/07/20 to 2020/07/26.
You cannot have both.
Assuming the latter to be correct and assuming ISO-8601 week definition, then your request can be re-phased as:
Given a specified date, if that date falls in the same week as the
current date then return the dates from the start of the week to the
specified date, inclusive. If the specified date does not fall in the
current week return the dates return the dates from Monday on or prior
to the specified date through Sunday on or after the specified date, inclusive.
The following implements that.
with targets (for_week_containing_date
,from_week_start
,iso_from_week
,iso_this_week) as
( select &for_week_containing_date
, date_trunc('week', &for_week_containing_date)
, extract(week from &for_week_containing_date)
, extract(week from now())
)
select user, date_sent
from user_days
cross join targets
where 1=1
and date_sent >= from_week_start
and date_sent <= case when iso_from_week = iso_this_week
then for_week_containing_date
else from_week_start + interval '6 days'
end
;
Since I do not care much for substitution variables this would need bound variables from a script, or wrap wrap it in an SQL function. See example of that here. Also note the last 2 queries, make sure you are ok with and understand what's happening around year end. You may need to make end of year/ begin of year adjustments. The results are not from being in a function, but result from ISO-8601 definitions. End of year/Begin year checking is needed any time you deal with date ranges.

Count and records from yesterday and add datecolumn next to it with yesterday's date in Bigquery, standardSQL

I've been able to get a sql running where I grab the count of all records from the day before.
SELECT count(*)
FROM mytable
WHERE date(ingest_time) >= (DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)) AND
date(ingest_time) < (CURRENT_DATE());
Adding to the SQL above in Bigquery, how do I generate a date column next to it that shows that these records are from yesterday with the date.
Something like this:
1) 3000390 | 2019-11-13
Instead of SELECT count(*) use SELECT count(*), DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)

Retrieve Records for month,datewise group by day in postgres

I have table time_slot where i have columns like date,start_time,end_time,user.
I want to retrieve records like say if I give the month and year along with user, what is the slots available for a particular user day wise for a month. Say user can have 3slots on a day & 0 on a day.
I am using Postgres and my date column is a date, time column is time. I am trying to do this in a Java web application and the date will be picked using a jquery datepicker. From where I'm sending as month, year and user.
Sample Data of table.
Date start-time end-time user
2019-09-01 12:21:34 13:21:34 user1
2019-09-01 14:21:34 15:21:34 user1
2019-09-01 17:21:34 17:21:34 user1
2019-09-03 12:21:34 13:21:34 user1
2019-09-03 12:21:34 13:21:34 user1
I would like to create a query that gives the time-slots of user concating start-time & end-time column and groups the results by date for a month as follows:
Date count_of_slots
2019-09-01 3
2019-09-02 0
2019-09-03 2
I have tried the below Query.
select distinct kt.start_time,kt.end_time,DATE(kt.slot_date),count(kt.slot_date)
from time_slot as kt
WHERE date_trunc('month',to_timestamp(kt.start_time, 'yy-mm-dd HH24:MI:SS.MS') + interval '1 day')
= date_trunc('month',to_timestamp(:startdate, 'yy-mm-dd HH24:MI:SS.MS') + interval '1 day' )
group by DATE(kt.slot_date) order by cb.start_time.
After getting result as expected above format, I need to loop through date to get the time-slots for that day and store in json as below.
{
"Date" : "2019-09-01",
"count" : "3",
"time-slot" : [
"12:21:34 - 13:21:34","14:21:34 - 15:21:34","17:21:34 - 17:21:34"]
}
Any suggestion and leads are welcomed.
Disclaimer: You should really upgrade your Postgres version!
demo:db<>fiddle
You need to join a date series against your data set. This can be done using the generate_series() function.
SELECT
gs::date,
COUNT(the_date)
FROM
time_slot ts
RIGHT JOIN
generate_series('2019-09-01', '2019-09-05', interval '1 day') gs ON ts.the_date = gs
GROUP BY gs
If you want to get the time_slots as well, simply add:
ARRAY_AGG(start_time || ' - ' || end_time) AS time_slot

count data in current month - not 30 days back Postgres statment

Ive this query which return data for 30 days from current date , need to modify it to return data for current month only not 30 days from current date
SELECT count(1) AS counter FROM users.logged WHERE createddate >=
date_trunc('month', CURRENT_DATE);
any tips how to tweak this query , at based on Postgres
regards
Something like this should work.
SELECT count(1) AS counter
FROM users.logged
WHERE date_trunc('month', createddate) = date_trunc('month', current_date);
It is already supposed to return the values in current month. Truncation does the conversion 10 Nov 2013 14:16 -> 01 Nov 2013 00:00 and it will return the data since the beginning of this month. The problem seems to be something else.
Ive this query which return data for 30 days from current date , need to modify it to return data for current month only not 30 days from current date
That's incorrect. Your query:
SELECT count(1) AS counter FROM users.logged WHERE createddate >= date_trunc('month', CURRENT_DATE);
returns all dates >= Nov 1st 00:00:00, in other words what you say that you want already. Or then, you've simplified your query and left out the more important bits — those that are broken. If not:
It might be that you've dates in the future and that you're getting incorrect counts as a result. If so, add an additional criteria in the where clause:
AND created_date < date_trunc('month', CURRENT_DATE) + interval '1 month'
It might also be that your sample data has a bizarre row with a time zone such that it looks like the timestamp is from this month but the date/time arithmetics land it last month.
This is will give you data for the current month only. I try to extract month and year. The last step is you can compare created date against current date-time.
SELECT count(1) AS counter
FROM users.logged
WHERE
EXTRACT(MONTH FROM createddate) = EXTRACT(MONTH FROM current_date)
AND EXTRACT(YEAR FROM createddate) = EXTRACT(YEAR FROM current_date);