Counting and adding distinct values that occur in certain dates using PostgreSQL - sql

Using some SQL in the tables of some database, I get a result like this:
id name date status
1 John 2018-05-03 PRESENT
2 Mary 2018-05-03 NOT PRESENT
3 Jane 2018-05-03 NOT PRESENT
2 Mary 2018-05-04 PRESENT
1 John 2018-05-04 PRESENT
1 John 2018-05-05 PRESENT
2 Mary 2018-05-05 NOT PRESENT
3 Jane 2018-05-04 PRESENT
3 Jane 2018-05-05 NOT PRESENT
1 John 2018-05-06 PRESENT
I wanna use further SQL to get in a result like this one:
id name date present not present
1 John 2018-05 4 0
2 Mary 2018-05 1 2
3 Jane 2018-05 2 1
In other words, I wanna extract how many classes a student attended in a given month, based on the status he/she received everyday. How can I achieve that?

Use conditional aggregation :
select id, name, to_char(date,'YYYY-MM') as "Date",
sum(case when status = 'PRESENT' then 1 else 0 end ) as present,
sum(case when status = 'NOT PRESENT' then 1 else 0 end ) as not_present
from tab
group by id, name, "Date"
order by id
Demo
keeping else 0 is important to get 0 for null returning cases
column alias in the select list might be used in the group by list
for Postgres
due to the desired output, truncating date value to month by
to_char(date,'YYYY-MM') is needed

select id, name, to_char(date,'YYYY-MM') as date,
sum((case when status = 'PRESENT' then 1 end )) present,
sum((case when status = 'NOT PRESENT' then 1 end )) not_present
from your_result_table
group by id, name, to_char(date,'YYYY-MM')

Use conditional aggregation (using filter) and date_trunc():
select id, name, date_trunc('month', date),
count(*) filter (where status = 'PRESENT') as num_present,
count(*) filter (where status = 'NOT PRESENT') as num_notpresent
from t
group by id, name, date_trunc('month', date)
order by id, name, date_trunc('month', date)

Related

SQL Troubleshooting Help on Table Structure

I'm attempting to calculate average number of days between a customer's 1st and 3rd purchase, but struggling to get the data ordered in a way that will allow me to calculate.
I currently have the below data table. (Note: Order sequence number refers to the number order for that customer.)
Order Date
Customer Number
Order Sequence Number
2020-09-20
1
1
2021-01-20
1
2
2021-01-21
1
3
2020-10-01
2
1
2020-08-06
3
1
2020-09-06
3
2
2020-09-09
3
3
I've been trying to get the data to look like the following table. [To then be able to calculate datediff on the last two columns.]
Customer Number
Order Count
First Order Date
Third Order Date
1
3
2020-09-20
2021-01-21
2
1
2020-10-01
Null
3
3
2020-08-06
2020-09-09
I've completely messed up the code, but here's what I've been trying.
CREATE TABLE X2 as
SELECT
customer_number,
max(order_sequence_number) as order_count,
CASE
WHEN order_sequence_number = 1 then order_date
ELSE null
END as first_order_date,
CASE
WHEN order_sequence_number = 3 then order_date
ELSE null
END as third_order_date
FROM X1
GROUP BY customer_number;
Can someone please tell me what I'm missing? Thanks in advance!
You are on the right track but you need aggregation functions:
SELECT customer_number,
max(order_sequence_number) as order_count,
MAX(CASE WHEN order_sequence_number = 1 THEN order_date END) as first_order_date,
MAX(CASE WHEN order_sequence_number = 3 THEN order_date END) as third_order_date
FROM X1
GROUP BY customer_number;
To get the difference in days, you would just subtract the two expressions using whatever date arithmetic is supported in your database.

Using Previously Calculated Values in a CASE Statement

I currently working on this Oracle database to figure out inactive relationships based on many conditions.
So currently I have a CASE statement to calculate the 'Status' field by using the last login date.
Following are the condition I have to check.
Last login date is within 6 months then set the status as Active - This I already did.
Last Login date is older than 6 months and if the user has another account/s which has an active status which was calculated in the previous condition, then make the second/multiple account/s Status as Active as well.
This one I'm unable to achieve.
I tried to select the resultant table in to a FROM clause once again hoping that I can populate the data. but I do not understand how to write that piece.
SELECT t1.UserName,
t1.UserID,
t1.LastLoginDate,
t1.status
FROM (SELECT UserName,
UserID,
LastLoginDate,
(CASE
WHEN LastLoginDate > ADD_MONTHS ('01-Jul-2019', -6)
THEN
'Active'
END)
AS status
FROM User_Mas_Table) t1
Above query gives me the following results.
UserName UserID LastLoginDate STATUS
---------- ---------- --------------- ------
AAAAAA 1 7/23/2019 Active
AAAAAA 2 7/24/2019 Active
AAAAAA 3 11/7/2018
CCCCCC 4 7/24/2019 Active
BBBBBB 5 4/30/2019 Active
DDDDDD 6 5/24/2019 Active
EEEEEE 7 7/22/2019 Active
FFFFFF 8 3/14/2019 Active
GGGGGG 9 7/24/2019 Active
GGGGGG 10 5/14/2018
HHHHHH 11 4/30/2019 Active
I need to fill those empty ones as active as well.
Use a window function to compare the most recent login date over all user accounts:
select um.*,
(case when max(lastlogindate) over (partition by username) > add_months(date '2019-07-01', -6)
then 'Active'
end) as status
from User_Mas_Table um;
If you only want "active" when the account has a lastlogindate, then the logic is:
select um.*,
(case when lastlogindate is not null and
max(lastlogindate) over (partition by username) > add_months(date '2019-07-01', -6)
then 'Active'
end) as status
from User_Mas_Table um;

Case statement for HIVE platform

I have a table with the following columns:
ID
Scheduled Date
Status
Target Date
I need to extract 'Status' corresponding to minimum 'Appointment Date' for each ID. If not available then I need to extract status corresponding to the minimum 'Target Date' for that ID.
Sample data:
ID | Scheduled_Date | Status | Target_Date
1 12/11/2017 Completed 12/11/2017
1 12/12/2017 Completed 12/12/2017
2 12/13/2017 Completed 12/13/2017
3 12/14/2017 Pending 12/14/2017
3 12/15/2017 Pending 12/15/2017
4 Confirmed 12/18/2017
4 Confirmed 12/19/2017
5 12/14/2017 Completed 12/14/2017
5 12/15/2017 Pending 12/15/2017
Can you please correct the code that I am trying to write?
SELECT ID,
CASE WHEN ID IS NOT NULL THEN
CASE WHEN MIN(SCHEDULED_DATE) IS NOT NULL
THEN STATUS
ELSE
END
CASE WHEN MIN(TARGET_DATE) IS NOT NULL
THEN STATUS
ELSE ''
END
FROM FIRST_STATUS
Try this query.
SELECT id,
status
FROM yourtable t
WHERE COALESCE (Scheduled_Date,
Target_Date) IN
(SELECT MIN(COALESCE (Scheduled_Date,Target_Date))
FROM yourtable i
WHERE i.ID = t.id
GROUP BY i.ID);
DEMO
Use row_number() analytic function:
select id,
status
from
(
select id,
status,
row_number() over(partition by id, order by nvl(Scheduled_Date,Target_Date)) rn
from yourtable t
)s
where rn=1
;

SQL query to group by data but with order by clause

I have table booking in which I have data
GUEST_NO HOTEL_NO DATE_FROM DATE_TO ROOM_NO
1 1 2015-05-07 2015-05-08 103
1 1 2015-05-11 2015-05-12 104
1 1 2015-05-14 2015-05-15 103
1 1 2015-05-17 2015-05-20 101
2 2 2015-05-01 2015-05-02 204
2 2 2015-05-04 2015-05-05 203
2 2 2015-05-17 2015-05-22 202
What I want is to get the result as.
1 ) It should show output as Guest_no, Hotel_no, Room_no, and column with count as number of time previous three column combination repeated.
So OutPut should like
GUEST_NO HOTEL_NO ROOM_NO Count
1 1 103 2
1 1 104 1
1 1 101 1
2 2 204 1
etc. But I want result to in ordered way e.g.: The output should be order by bk.date_to desc
My query is as below its showing me count but if I use order by its not working
select bk.guest_no, bk.hotel_no, bk.room_no,
count(bk.guest_no+bk.hotel_no+bk.room_no) as noOfTimesRoomBooked
from booking bk
group by bk.guest_no, bk.hotel_no, bk.room_no, bk.date_to
order by bk.date_to desc
So with adding order by result is showing different , because as I added order by date_to column so i have to add this column is group by clause too which will end up in different result as below
GUEST_NO HOTEL_NO ROOM_NO Count
1 1 103 1
1 1 104 1
1 1 103 1
1 1 101 1
2 2 204 1
Which is not the output I want.
I want these four column but with order by desc of date_to column and count as no of repetition of first 3 columns
I think a good way to do this would be grouping by guest_no, hotel_no and room_no, and sorting by the maximum (i.e. most recent) booking date in each group.
SELECT
guest_no,
hotel_no,
room_no,
COUNT(1) AS BookingCount
FROM
booking
GROUP BY
guest_no,
hotel_no,
room_no
ORDER BY
MAX(date_to) DESC;
Maybe this is what you're looking for?
select
guest_no,
hotel_no,
room_no,
count(*) as Count
from
booking
group by
guest_no,
hotel_no,
room_no
order by
min(date_to) desc
Or maybe max() instead of min(). SQL Fiddle: http://sqlfiddle.com/#!6/e684c/3
You could try this.
select t.* from
(
select bk.guest_no, bk.hotel_no, bk.room_no, bk.date_to,
count(*) as noOfTimesBooked from booking bk
group by bk.guest_no, bk.hotel_no, bk.room_no, bk.date_to
) t
order by t.date_to
You will also have to select date_to and then group the result by it.
If you use 'group by' clause, SQL Server doesn't allow you to use 'order by'. So you can make a sub query and use 'order by' in the outer query.
SELECT * FROM
(select bk.guest_no,bk.hotel_no,bk.room_no
,count(bk.guest_no+bk.hotel_no+bk.room_no) as noOfTimesRoomBooked,
(SELECT MAX(date_to) FROM booking CK
WHERE CK.guest_no=BK.guest_no AND bk.hotel_no=CK.bk.hotel_no
bk.room_no=CK.ROOM_NO ) AS DATEBOOK
from booking bk
group by bk.guest_no,bk.hotel_no,bk.room_no,bk.date_to) A
ORDER BY DATEBOOK
IT MIGHT HELP YOU

SQL Group By Help Required

I have a table named People in the following format:
Date | Name.
When I count the people by Grouping By Name with
Select Date, Name, count(*)
From People
Group By Date, Name;
Will give the following
Date Name count(*)
10 Peter 25
10 John 30
10 Mark 25
11 Peter 15
11 John 10
11 Mark 5
But I would like the following result:
Date Peter John Mark
10 25 30 25
11 15 10 5
Is this possible? This is a simple example of a more complicated database. If someone helps me in solving this problem I will use the concept to implement it in my table
Thanks!
Select Date
, count(case when Name = 'Peter' then 1 else null end)
, count(case when Name = 'John' then 1 else null end)
, count(case when Name = 'Mark' then 1 else null end)
From People
Group By Date;
another option different from turbanoff's if, for some reason, you find yourself in a situation that you cant apply a group by:
Select distinct(P.Date),
(select count(*) from People where date=p.date and name='Peter') as Peter,
(select count(*) from People where date=p.date and name='John') as John,
(select count(*) from People where date=p.date and name='Mark') as Mark
From People P