Group Results By Month and Column - postgresql

Is there anyway i can group the results by month and by type? With the query below i managed to group by month but the "type" is not grouping.
query:
select date_trunc('month',processingdate),type,sum(itemcount), sum(itemamount)
from test
where date_trunc('month',processingdate) >= now() - interval '1 month'
group by type,date_trunc('month',processingdate)
order by processingdate
Data in table:
date_trunc type sum sum
1/1/20 11 5 1
1/2/20 12 3 2
1/3/20 11 2 3
1/4/20 12 3 5
Expected Results:
date_trunc type sum sum
1/1/2020 11 7 4
1/1/2020 12 6 7

Related

Group by Day or Most Recent Value Postgresql

I have the following table using postgresql:
Date Group Count Days
31/01/2021 Gr1 50 5
30/01/2021 Gr2 40 10
29/01/2021 Gr1 30 6
28/01/2021 Gr2 20 4
27/01/2021 Gr1 10 5
26/01/2021 Gr2 40 8
25/01/2021 Gr1 30 6
24/01/2021 Gr2 10 5
23/01/2021 Gr1 5 1
What I want to is produce a table for group 1 (GR1) by day, produce the count and calculate 'Average Count Per Day' as Count/Days. Where GR1 is not produced for a day then use the previous days which was a GR1 day. For example where GR1 does not have a value for 30-01-2021 then use the values from the most recent earlier day which it was GR (i.e. 29-01-2021).
The result should look like this:
Date Group Count Days Avg Count Per Days
31/01/2021 Gr1 50 5 10
30/01/2021 Gr1 30 6 5
29/01/2021 Gr1 30 6 5
28/01/2021 Gr1 10 5 2
27/01/2021 Gr1 10 5 2
26/01/2021 Gr1 30 6 5
25/01/2021 Gr1 30 6 5
24/01/2021 Gr1 5 1 5
23/01/2021 Gr1 5 1 5
First I get all rows where "Group" = 'Gr1' and calculate "Avg Count Per Days" (subquery grp1). Then I generate all days between MIN("Date") and MAX("Date") (subquery days). Finally I JOIN boths subqueries and for each day I get most recent value not null (actual value or previous most recent value), using window function FIRST_VALUE():
WITH grp1 AS (SELECT *, "Count" / "Days" AS "Avg Count Per Days"
FROM t
WHERE "Group" = 'Gr1'),
days AS (SELECT generate_series(MIN("Date"), MAX("Date"), INTERVAL '1 day')::date AS day
FROM grp1)
SELECT DISTINCT
days.day AS "Date",
FIRST_VALUE("Group") OVER (PARTITION BY days.day ORDER BY "Date" DESC) AS "Group",
FIRST_VALUE("Count") OVER (PARTITION BY days.day ORDER BY "Date" DESC) AS "Count",
FIRST_VALUE("Days") OVER (PARTITION BY days.day ORDER BY "Date" DESC) AS "Days",
FIRST_VALUE("Avg Count Per Days") OVER (PARTITION BY days.day ORDER BY "Date" DESC) AS "Avg Count Per Days"
FROM days
LEFT JOIN grp1 ON grp1."Date" <= days.day
ORDER BY days.day DESC;
I assuming you have not more than 1 row "Group" = 'Gr1' by day.

Getting ranking based on a number from CTE

I have a complex situation in PostgreSQL 11 where i need to generate a numbering based on a single figure which i get it from a CTE.
Below is the CTE
WITH pending_orders_to_be_processed_details
AS
(
SELECT ROW_NUMBER() OVER(ORDER BY so.create_date ) as queue_no
, name,so.create_date ::TIMESTAMP
FROM picking sp
LEFT JOIN order so ON so.name=sp.origin
WHERE sp.state IN('assigned','confirmed')
)
,orders_which_can_be_processed_today AS
(
-- This CTE will give me a count of orders
and its hourly average, Lets say count is 400 and hourly avg is 3
)
Now i need to number the details according to the hourly average, Means the first 3 orders need to be ranked as 1, next 3 to be ranked as 2 and so on, so that i can able to identify that these can be processed based on this ranking.
Input will be
name queu_number. create_date
so1 1 2021-03-11 12:00:00
so2 2 2021-03-11 13:00:00
so3 3 2021-03-11 14:00:00
so4 4 2021-03-11 15:00:00
so5 5 2021-03-11 16:00:00
so6 6 2021-03-11 17:00:00
so7 7 2021-03-11 18:00:00
so8 8 2021-03-11 19:00:00
so9 9 2021-03-11 20:00:00
The expected output will be
name rank
so1 1
so2 1
so3 1
so4 2
so5 2
so6 2
so7 3
so8 3
so9 3
Any help/suggestions.
Edit: I recently learned about a function, which fits well here:
demo:db<>fiddle
You can use the ntile() window function for that:
SELECT
*,
ntile(3) OVER (ORDER BY create_date)
FROM mytable
demo:db<>fiddle
Since you already created a cumulative row count, you can use this to create your expected rank:
SELECT
*,
floor((queue_no - 1) / 3) + 1 as rank
FROM my_cte
queue_no - 1 (so, 1 to 3 will be shifted to 0 to 2)
Diff by 3: so, 0 to 2 will be 0.x and 3 to 5 will be 1.x, ...
Now round these result to 0, 1, 2, ...
If you want to start with 1 instead of 0, add 1

Getting data from alternate dates of same ID column

I've a table data as below, now I need to fetch the record with in same code, where (Value2-Value1)*2 of one row >= (Value2-Value1) of consequtive date row. (all dates are uniform with in all codes)
---------------------------------------
code Date Value1 Value2
---------------------------------------
1 1-1-2018 13 14
1 2-1-2018 14 16
1 4-1-2018 15 18
2 1-1-2019 1 3
2 2-1-2018 2 3
2 4-1-2018 3 7
ex: output needs to be
1 1-1-2018 13 14
as I am begginer to SQL coding, tried my best, but cannot get through with compare only on consequtive dates.
Use a self join.
You can specify all the conditions you've listed in the ON clause:
SELECT T0.code, T0.Date, T0.Value1, T0.Value2
FROM Table As T0
JOIN Table As T1
ON T0.code = T1.code
AND T0.Date = DateAdd(Day, 1, T1.Date)
AND (T0.Value2 - T0.Value1) * 2 >= T1.Value2 - T1.Value1

How can I evaluate data over time in Postgresql?

I need to find users who have posted three times or more, three months in a row. I wrote this query:
select count(id), owneruserid, extract(month from creationdate) as postmonth from posts
group by owneruserid, postmonth
having count(id) >=3
order by owneruserid, postmonth
And I get this:
count owneruserid postmonth
36 -1 1
23 -1 2
45 -1 3
41 -1 4
18 -1 5
24 -1 6
31 -1 7
78 -1 8
83 -1 9
17 -1 10
88 -1 11
127 -1 12
3 6 11
3 7 12
4 8 1
8 8 12
4 12 4
3 12 5
3 22 2
4 22 4
(truncated)
Which is great. How can I query for users who posted three times or more, three months or more in a row? Thanks.
This is called the Islands and Gaps problem, specifically it's an Island problem with a date range. You should,
Fix this question up.
Flag it to be sent to dba.stackexchange.com
To solve this,
Create a pseudo column with a window that has 1 if the row preceding it does not correspond to the preceding mont
Create groups out of that with COUNT()
Check to make sure the count(*) for the group is greater than or equal to three.
Query,
SELECT l.id, creationdaterange, count(*)
FROM (
SELECT t.id,
t.creationdate,
count(range_reset) OVER (PARTITION BY t.id ORDER BY creationdate) AS creationdaterange
FROM (
SELECT id,
creationdate,
CASE
WHEN date_trunc('month',creationdate::date)::date - interval '1 month' = date_trunc('month',lag(creationdate))::date OVER (PARTITION BY id ORDER BY creationdate)
THEN 1
END AS range_reset
FROM post
ORDER BY id, creationdate
) AS t;
) AS l
GROUP BY t.id, creationdaterange
HAVING count(*) >= 3;

How to get last 3 Months of "Monday to Sunday" dates In Redshift?

How can I get last 3 Months of "Monday to Sunday" dates in Redshift?
S.no Start_dt End_dt week
1 18-Jul-16 24-Jul-16 Week1
2 25-Jul-16 31-Jul-16 Week2
3 1-Aug-16 7-Aug-16 Week3
4 8-Aug-16 14-Aug-16 Week4
5 15-Aug-16 21-Aug-16 Week5
6 22-Aug-16 28-Aug-16 Week6
7 29-Aug-16 4-Sep-16 Week7
8 5-Sep-16 11-Sep-16 Week8
9 12-Sep-16 18-Sep-16 Week9
10 19-Sep-16 25-Sep-16 Week10
11 26-Sep-16 2-Oct-16 Week11
12 3-Oct-16 9-Oct-16 Week12
13 10-Oct-16 16-Oct-16 Week13
I've tried this:
select
trunc(date_trunc('week',sysdate)) st_dt,
trunc(date_trunc('week', sysdate)+6) ed_dt,
'week'||row_number() over (order by null) as week
but it only returns the current week's Monday and Sunday.
You can use generate_series() to generate a range of dates:
SELECT
trunc(day) as start_date,
trunc(day + 6) as end_date
FROM
(select date_trunc('week', sysdate) + (generate_series(1, 12) * interval '1 week') as day)
ORDER BY 1 ASC
This results in:
week start week end
2016-10-24 2016-10-30
2016-10-31 2016-11-06
2016-11-07 2016-11-13
2016-11-14 2016-11-20
2016-11-21 2016-11-27
2016-11-28 2016-12-04
2016-12-05 2016-12-11
2016-12-12 2016-12-18
2016-12-19 2016-12-25
2016-12-26 2017-01-01
2017-01-02 2017-01-08
2017-01-09 2017-01-15
Please note that generate_series() in Amazon Redshift cannot be joined with existing tables. It can only be used as a "Leader-only" query.