Extracting timestamps difference by day, minute and second in Postgresql - postgresql

I would like to get the difference between 2 timestamps both have the day and month but I would like to see the output as the largest value. Currently my output is showing the difference in years as well as months and days etc, but I only need to see the days and hours. Is there a way to do this?
This is the data using this code:
select
id,
ts1 ,
ts2 ,
(ts2 - ts1) as output
from table_a
an example row (out of multiple):
id |ts1 | ts2 | output
---|-----------------------|-----------------------| --------------------
3 |2020-04-27 11:00:46.00 |2020-04-27 12:52:04.00 | 0 years 0 mons 0 days 1 hours 51 mins 18.00 secs
But I would like to show the shortest answer possible (so just days when necessary, hours, minutes and excluding seconds) so in this case just 1 hours 51 minutes etc
Desired result:
id |ts1 | ts2 | output
----|-----------------------|-----------------------| --------------------
3 |2020-04-27 11:00:46.00 |2020-04-27 12:52:04.00 | 1 hours 51 mins
How do I do this (using postgresql) ?

Related

Group by day of the month (series) as well as a location

I have come across the following link How to get list day of month data per month in postgresql and am building on this for my own query. Which shows a simple use of generate series for a listing of dates. I have a table that has dates, number of users and a location, which I would like to report on monthly, and on the days which have no data, simply show zero. I think the issue I am having is with the grouping of the location, as that is where my results go astray currently from what is expected.
My data (table = reserve)
Date | Users | Location
-----------------------
2021-05-02 | 3 | 1100<br>
2021-05-24 | 4 | 1000<br>
2021-05-26 | 6 | 1000<br>
2021-05-28 | 7 | 1100<br>
2021-05-29 | 4 | 1100<br>
2021-05-27 | 3 | 1000<br>
etc.
If I use the generate_series for the entire month (generate_series('2021-06-01', '2021-10-31', '1 day'::interval) and then join to the reserve table for each of the locations, the issue is that the group by will exclude the blank days on the join.
I am hoping to achieve:
Date
2021-05-01 | 0 | 1000<br>
2021-05-02 0 1000<br>
....<br>
2021-05-24 4 1000<br>
Until end of month<br>
2021-05-01 0 1100<br>
2021-05-02 3 1100<br>
....
Until end of month
Thank you in advance.
It's hard to tell exactly what you're after based on the example data from your tables but if you don't want to eliminate rows where there is no match this is exactly what a LEFT JOIN is for.
For example:
SELECT * FROM generate_series('2021-06-01', '2021-10-31', '1 day'::interval) as d
LEFT JOIN reserve r ON r.the_date = d;
This will keep all the days in the sequence and just returns null for the columns where there was no match for that day. You can see this in action with this SQL fiddle example

T_SQL counting particular values in one row with multiple columns

I have little problem with counting cells with particular value in one row in MSSMS.
Table looks like
ID
Month
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
11
12
13
14
15
16
...
31
5000
1
null
null
1
1
null
1
1
null
null
2
2
2
2
2
null
null
3
3
3
3
3
null
...
1
I need to count how many cells in one row have value for example 1. In this case it would be 5.
Data represents worker shifts in a month. Be aware that there is a column named month (FK with values 1-12), i don't want to count that in a result.
Column ID is ALWAYS 4 digit number.
Possibility is to use count(case when) but in examples there are only two or three columns not 31. Statement will be very long. Is there any other option to count it?
Thanks for any advices.
I'm going to strongly suggest that you abandon your current table design, and instead store one day per month, per record, not column. That is, use this design:
ID | Date | Value
5000 | 2021-01-01 | NULL
5000 | 2021-01-02 | NULL
5000 | 2021-01-03 | 1
5000 | 2021-01-04 | 1
5000 | 2021-01-05 | NULL
...
5000 | 2021-01-31 | 5
Then use this query:
SELECT
ID,
CONVERT(varchar(7), Date, 120),
COUNT(CASE WHEN Value = 1 THEN 1 END) AS one_cnt
FROM yourTable
GROUP BY
ID,
CONVERT(varchar(7), Date, 120);

Aggregate data to 30 minute intervals

A have a table where each row is 300 seconds (or 5 minutes) apart. I need to aggregate the data on every hour and half hour, aggregating everything before and including the hour or half hour.
I've tried this code:
SELECT
to_timestamp(floor(a / 1800 )) *
1800)
AT TIME ZONE 'UTC' as interval_alias, SUM(b) as b_sum
FROM TABLE_NAME GROUP BY interval_alias
...and it aggregates the data on every hour and half hour, but it sum the values post the hour and half hour.
The table looks something like this:
a | b
-------------------------
1533045600 | 3
1533045900 | 5
1533046200 | 6
1533046500 | 3
1533046800 | 5
1533047100 | 2
1533047400 | 3
1533047700 | 8
1533048000 | 5
1533048300 | 5
1533048600 | 6
The actual result with the above code is:
a | b
-------------------------
1533045600 | 24
1533047400 | 27
The desired output is:
a | b
-------------------------
1533045600 | 3
1533047400 | 24
I used a simpler calculation for the interval_alias and with a GROUP BY you can only select aggregations or the columns that are part of the GROUP BY. (The SELECT * you posted in the question didn't look correct...)
SELECT
FLOOR(a/1800)*1800 AS interval_alias,
SUM(b) AS sum_b
FROM TABLE_NAME
GROUP BY interval_alias
See example code on SQL Fiddle
update:
This is close to your desired output but will include a third result as your test data spans over more than a half hour.
SELECT
FLOOR(a/1800)*1800 + SIGN(a%1800)*1800 AS interval_alias,
SUM(b) AS sum_b
FROM TABLE_NAME
GROUP BY interval_alias
ORDER BY interval_alias

Convert day of year (from extract) back to a date

I am trying to group data by the day of the year that it falls on. I have been able to achieve this with the code below. The issue is that I lose the information as to which day (i.e. Jan 1st, Jan 2nd etc) each grouping represents. I am simply left with a number (e.g. 1, 2 etc.) representing the day of the year. Is there any to convert this number back into the more descriptive date? Thanks a lot.
CREATE TABLE tmp2 AS
SELECT extract(doy from trd_exctn_dt) as day_of_year
,sum(dollar_vol) AS dollar_vol
FROM tmp
GROUP BY extract(doy from trd_exctn_dt);
Current Output:
day_of_year | dollar_vol
------------|------------
1 10
2 15
3 7
Desired Output: N.b. The exact format of the first column doesn't matter too much. I would be happy with DD/MM, MM/DD or any other clear output.
day_of_year | dollar_vol
------------|------------
Jan 1 | 10
Jan 2 | 15
Jan 3 | 7
Using the to_char fucntion:
SELECT to_char(trd_exctn_dt,'MM/DD') as day_of_year ,sum(dollar_vol) AS dollar_vol
FROM tmp
GROUP BY day_of_year ;

how do you group query by hours?

I'm trying to query surveys completed every hour in a given day.
the survey table is something like this:
id(SERIAL) - userid(INTEGER) - description - timeTaken(timestamp with time zone)
3 ; 1; "some random description"; "2015-01-17 04:30:24.983576-05"
5 ; 2; "sample about x"; "2015-01-17 04:30:24.983576-05"
7 ; 3; "survey about ducks"; "2015-01-17 05:30:24.983576-05"
basically for a given day lets say March 1st, I want to get all the survey rows grouped by the hour they were taken, i.e 7 rows at 1pm, 3 at 2pm, etc. But I'm not sure if its possible to group like this on pg or if I should do it client end.
EDIT: for the data above have id 3 and 5 grouped under 4 and id 7 grouped for 5. basically I want to display the data seperated by the hours they were completed in.
Thanks
You can use date_part to extract just the hour, which you can have in your group by clause. See http://www.postgresql.org/docs/9.4/static/functions-datetime.html.
By using extarct function in postgresql
for the following sample data
id userid descp timetaken
-- ------ ----------------------- ---------------------------
1 1 some random description 2015-01-17 15:00:24.9835760
2 2 sample about x 2015-01-17 15:00:24.9835760
3 3 survey about ducks 2015-01-17 16:00:24.9835760
4 3 survey about ducks 2015-01-01 19:00:24.9835760
5 3 survey about ducks 2015-01-01 16:00:24.9835760
6 3 survey about ducks 2015-01-01 19:00:24.9835760
I need to get the survey_count per hour in date 01-01-2015
select extract(hour from timetaken) survey_hour
,count(*) survey_count
from sur
where timetaken::date ='2015-01-01'
group by survey_hour