How to get max of one date in a table in sql [duplicate] - sql

This question already has answers here:
Fetch the rows which have the Max value for a column for each distinct value of another column
(35 answers)
GROUP BY with MAX(DATE) [duplicate]
(6 answers)
Oracle SQL query: Retrieve latest values per group based on time [duplicate]
(2 answers)
Return row with the max value of one column per group [duplicate]
(3 answers)
Get value based on max of a different column grouped by another column [duplicate]
(1 answer)
Closed 2 years ago.
I have written the below code -
select
PAPF.PERSON_NUMBER,
BP.NAME BENEFIT_PLAN,
BBR.BENEFIT_RELATION_NAME,
Round(BPER.BNFT_AMT, 2) * 100 COVERAGE_AMOUNT,
TO_CHAR(BPER.ENRT_CVG_STRT_DT, 'YYYYMMDD') ENROLMENTCOVSTARTDATE
TO_CHAR(BPER.ENRT_CVG_THRU_DT, 'YYYYMMDD') ENROLMENTCOVSENDDATE
FROM PER_ALL_PEOPLE_F PAPF,
BEN_PRTT_ENRT_RSLT BPER,
BEN_PL_F BP,
BEN_BENEFIT_RELATIONS_F BBR
WHERE PAPF.PERSON_ID = BPER.PERSON_ID
AND BPER.PL_ID = BP.PL_ID
AND BBR.PERSON_ID = PAPF.PERSON_ID
AND BBR.BENEFIT_RELATION_NAME = 'DFLT'
AND SYSDATE BETWEEN PAPF.EFFECTIVE_START_DATE AND PAPF.EFFECTIVE_END_DATE
AND SYSDATE BETWEEN BP.EFFECTIVE_START_DATE AND BP.EFFECTIVE_END_DATE
AND SYSDATE BETWEEN BBR.EFFECTIVE_START_DATE AND BBR.EFFECTIVE_END_DATE
This will give me an output like -
PErson_number BENEFIT_PLAN COVERAGE_AMOUNT ENROLMENTCOVSTARTDATE ENROLMENTCOVSENDDATE
1010 US Basic PLAN 20000 20200901 20201020
1010 US Basic PLAN 20000 20201021
1011 Us Spouse PLAN 160000 20200901 20201020
1011 Us Spouse PLAN 160000 20201021 47121231
I want to retrive only the max of the ENROLMENTCOVSTARTDATE for each person. The expected output should be -
PErson_number BENEFIT_PLAN COVERAGE_AMOUNT ENROLMENTCOVSTARTDATE ENROLMENTCOVSENDDATE
1010 US Basic PLAN 20000 20201021
1011 Us Spouse PLAN 160000 20201021 20201220
how can i use Max in the main query for this ?

First rank the rows by their ENRT_CVG_STRT_DT per person (assumed identified by PAPF.PERSON_NUMBER). Then filter on rows that are top.
select person_number,
name,
BENEFIT_PLAN,
BENEFIT_RELATION_NAME,
COVERAGE_AMOUNT,
ENROLMENTCOVSTARTDATE,
ENROLMENTCOVSENDDATE
from (
select
PAPF.PERSON_NUMBER,
BP.NAME BENEFIT_PLAN,
BBR.BENEFIT_RELATION_NAME,
Round(BPER.BNFT_AMT, 2) * 100 COVERAGE_AMOUNT,
TO_CHAR(BPER.ENRT_CVG_STRT_DT, 'YYYYMMDD') ENROLMENTCOVSTARTDATE,
TO_CHAR(BPER.ENRT_CVG_THRU_DT, 'YYYYMMDD') ENROLMENTCOVSENDDATE,
row_number() over (partition by PAPF.PERSON_NUMBER order by BPER.ENRT_CVG_STRT_DT desc) rn
from
FROM PER_ALL_PEOPLE_F PAPF,
BEN_PRTT_ENRT_RSLT BPER,
BEN_PL_F BP,
BEN_BENEFIT_RELATIONS_F BBR
WHERE PAPF.PERSON_ID = BPER.PERSON_ID
AND BPER.PL_ID = BP.PL_ID
AND BBR.PERSON_ID = PAPF.PERSON_ID
AND BBR.BENEFIT_RELATION_NAME = 'DFLT'
AND SYSDATE BETWEEN PAPF.EFFECTIVE_START_DATE AND PAPF.EFFECTIVE_END_DATE
AND SYSDATE BETWEEN BP.EFFECTIVE_START_DATE AND BP.EFFECTIVE_END_DATE
AND SYSDATE BETWEEN BBR.EFFECTIVE_START_DATE AND BBR.EFFECTIVE_END_DATE
)
where rn = 1
If you want to accept tied first place then you would change row_number to rank/dense_rank (it won't matter if you're filtering on rn = 1). One would assume that there would only be one row per person per ENROLMENTCOVSTARTDATE though.

Related

Conditional aggregate queries [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I've seen other solutions. Curious if this method of solving these would work.
TABLES:
attendance_events : date | student_id | attendance
all_students : student_id | school_id | grade_level | date_of_birth | hometown
What percent of students attend school on their birthday?
With agg_join as (SELECT att.date as dates, att.attendance as attendance, als.date_of_birth as DOB, att.student_id as student_id
FROM attendance_events att
join all_students als on att.student_id = als.studentid)
Select count(DISTINCT student_id) as total_students,
count( Distinct case when DOB = dates and attendance = TRUE) as count_of_DOBS,
total_students/ count_of_DOBS as percent_of_student
from agg_join
Which grade level had the largest drop in attendance between yesterday and today?
With agg_join as ( SELECT att.date as dates, att.attendance as attendance, als.grade_level as grade
FROM attendance_events att
join all_students als on att.student_id = als.studentid)
Select grade,
case when dates ( 'd', -1, currentdate) and attendance = True then 1
else 0 end as yesterday_att,
case when dates ( 'd', currentdate) and attendance = True then 1
else 0 end as Today_att,
(Today_att - yesterday_att) * -1 AS DIFF
from agg_join
Group by grade
Order by DIFF DESC
Limit 1
What percent of students attend school on their birthday?
SELECT 100.0
* count(*) FILTER (WHERE EXISTS (SELECT FROM attendance_events a
WHERE a.student_id = s.student_id
AND f_mmdd(a.date) = f_mmdd(s.date_of_birth)
))
/ count(*) AS percentage
FROM all_students s;
Where the custom function f_mmdd() is defined here:
How do you do date math that ignores the year?
See:
Convert numeric result to percentage with decimal digits
About the aggregate FILTER clause:
Aggregate columns with additional (distinct) filters
Which grade level had the largest drop in attendance between yesterday and today?
SELECT s.grade_level
, count(*) FILTER (WHERE a.date = CURRENT_DATE - 1) AS yesterday_attendance
, count(*) FILTER (WHERE a.date = CURRENT_DATE) AS today_attendance
FROM attendance_events a
JOIN all_students s USING (student_id)
WHERE a.date IN (CURRENT_DATE, CURRENT_DATE -1) -- logically redundant
GROUP BY s.grade_level
ORDER BY today_attendance - yesterday_attendance
-- short for: yesterday_attendance - today_attendance DESC
LIMIT 1;
WHERE a.date IN (CURRENT_DATE, CURRENT_DATE -1) is logically redundant, but makes the query much faster.
Read up and try to understand why these work, if you are not solving them yourself.

Oracle/SQL -Sales broken out by Months

Hello I have created the following query to pull total order by month for a salesMen. while this gets me the data I need for a single salesmen i need to run this for more than just one. what I would like to accomplish is a query that pull for several different salesmen and is broken out by month and the Months being the Columns names(Columns dynamic to months being pulled). Like below.
SalesMen - 10-2017 - 11-2017 - 12-2017 - 01/2018
------------------------------------------------------------
Salesmen_1 Month_total(5) 15 300 100
Salesmen_2 100 948 821 684
Current Code:
select (case when region_code in ('123','124') then 'SalesMen_1' else 'N/A' end)SalesMen, to_char(DATE_ENTERED, 'MM-YYYY') as MM_YYYY, Count(ORder_NO) as Month_Total
from ORDERS
where
REGEXP_like (ORder_NO, '^W|^E')
and DATE_ENTERED between ADD_MONTHS(TO_DATE(TO_CHAR(ADD_MONTHS(SYSDATE, 2), 'YYYY') || '-01-01', 'YYYY-MM-DD'), -3) and TO_DATE(TO_CHAR(SYSDATE, 'YYYY-MM')|| '-01', 'YYYY-MM-DD') - 1
and region_code in ('123','124')
group by to_char(DATE_ENTERED, 'MM-YYYY'),(case when region_code in ('123','124') then 'SalesMen_1' else 'N/A' end)
order by to_char(DATE_ENTERED, 'MM-YYYY') desc
Results:
Current Results Example

How to add static values to SQL QUERY Result set in ORACLE

I have a SQL Query that works perfectly. I am using Oracle 11g. The current SQL Query lists upcoming flights for the next 6 months and then list all past flights afterwards. So my query lists all flights for 2018 first and then all old flights after dating back early as 1998. I need to add two static values to this query. The two static values I want to add are "UPCOMING FLIGHTS" and "PAST FLIGHTS" to distinguish which flights are new and old. How can I achieve this? I need to incorporate this added code with the current SQL query that I have below. I have not been able to do this.
Current SQL Query:
SELECT FLIGHT_NMBR, SCHEDULED_LAUNCH_DATE
FROM FLIGHTS
WHERE DATA_VERSION_NAME = 'WORKING'
AND sequence_nmbr >= 0
ORDER BY (CASE WHEN to_date(scheduled_launch_date, 'DD-MON-YY')
BETWEEN add_months(trunc(sysdate, 'MON'), 0)
AND add_months(trunc(sysdate, 'MON'), 6) THEN 1 ELSE 2 END),
(CASE WHEN to_date(scheduled_launch_date, 'DD-MON-YY')
BETWEEN add_months(trunc(sysdate, 'MON'), 0)
AND add_months(trunc(sysdate, 'MON'), 6) THEN SCHEDULED_LAUNCH_DATE END),
sequence_nmbr;
Results of current SQL query above:
FLIGHT_NMBR SCHEDULED
------------ ---------
SpX-14 26-JAN-18
69P 09-FEB-18
SpX-DM1 09-MAR-18
54S 13-MAR-18
OA-9 14-MAR-18
55S 29-APR-18
SpX-15 06-JUN-18
SpX-DM2 22-JUN-18
70P 27-JUN-18
1A/R 20-NOV-98
2A 04-DEC-98
How can I achieve the desired result set below:
FLIGHT_NMBR SCHEDULED
------------ ---------
UPCOMING FLIHGTS-------------------------------STATIC VALUE I WANT TO ADD
SpX-14 26-JAN-18
69P 09-FEB-18
SpX-DM1 09-MAR-18
54S 13-MAR-18
OA-9 14-MAR-18
55S 29-APR-18
SpX-15 06-JUN-18
SpX-DM2 22-JUN-18
70P 27-JUN-18
PAST FLIGHTS-----------------------------------STATIC VALUE I WANT TO ADD
1A/R 20-NOV-98
2A 04-DEC-98
Want my dropdown to look like this:
you can do it this way,
SELECT 'UPCOMING FLIHGTS' text, NULL sched
FROM dual
UNION ALL
<your select query for upcoming flights>
UNION ALL
SELECT 'PAST FLIGHTS' text, NULL sched
FROM dual
UNION ALL
<your select query for past flights>
What you want to do should be done at the application level. A SQL query returns a result set, which is a table -- consisting of rows with identical columns. Your new rows are not in the same format.
You can simplify the logic and include the flag on each row;
SELECT which, FLIGHT_NMBR, SCHEDULED_LAUNCH_DATE
FROM (SELECT F.*,
(CASE WHEN to_date(scheduled_launch_date, 'DD-MON-YY') BETWEEN add_months(trunc(sysdate, 'MON'), 0) AND add_months(trunc(sysdate, 'MON'), 6)
THEN 'UPCOMING' ELSE 'PAST'
END) as which
FROM FLIGHTS F
) F
WHERE DATA_VERSION_NAME = 'WORKING' AND sequence_nmbr >= 0
ORDER BY (CASE WHEN which = 'UPCOMING' THEN 1 ELSE 2 END),
(CASE WHEN which = 'UPCOMING' THEN SCHEDULED_LAUNCH_DATE END),
sequence_nmbr;

List all months with a total regardless of null

I have a very small SQL table that lists courses attended and the date of attendance. I can use the code below to count the attendees for each month
select to_char(DATE_ATTENDED,'YYYY/MM'),
COUNT (*)
FROM TRAINING_COURSE_ATTENDED
WHERE COURSE_ATTENDED = 'Fire Safety'
GROUP BY to_char(DATE_ATTENDED,'YYYY/MM')
ORDER BY to_char(DATE_ATTENDED,'YYYY/MM')
This returns a list as expected for each month that has attendees. However I would like to list it as
January 2
February 0
March 5
How do I show the count results along with the nulls? My table is very basic
1234 01-JAN-15 Fire Safety
108 01-JAN-15 Fire Safety
1443 02-DEC-15 Healthcare
1388 03-FEB-15 Emergency
1355 06-MAR-15 Fire Safety
1322 09-SEP-15 Fire Safety
1234 11-DEC-15 Fire Safety
I just need to display each month and the total attendees for Fire Safety only. Not used SQL developer for a while so any help appreciated.
You would need a calendar table to select a period you want to display. Simplified code would look like this:
select to_char(c.Date_dt,'YYYY/MM')
, COUNT (*)
FROM calendar as c
left join TRAINING_COURSE_ATTENDED as tca
on tca.DATE_ATTENDED = c.Date_dt
WHERE tca.COURSE_ATTENDED = 'Fire Safety'
and c.Date_dt between [period_start_dt] and [period_end_dt]
GROUP BY to_char(c.Date_dt,'YYYY/MM')
ORDER BY to_char(c.Date_dt,'YYYY/MM')
You can create your own set required year month's on-fly with 0 count and use query as below.
Select yrmth,sum(counter) from
(
select to_char(date_attended,'YYYYMM') yrmth,
COUNT (1) counter
From TRAINING_COURSE_ATTENDED Where COURSE_ATTENDED = 'Fire Safety'
Group By Y to_char(date_attended,'YYYYMM')
Union All
Select To_Char(2015||Lpad(Rownum,2,0)),0 from Dual Connect By Rownum <= 12
)
group by yrmth
order by 1
If you want to show multiple year's, just change the 2nd query to
Select To_Char(Year||Lpad(Month,2,0)) , 0
From
(select Rownum Month from Dual Connect By Rownum <= 12),
(select 2015+Rownum-1 Year from Dual Connect By Rownum <= 3)
Try this :
SELECT Trunc(date_attended, 'MM') Month,
Sum(CASE
WHEN course_attended = 'Fire Safety' THEN 1
ELSE 0
END) Fire_Safety
FROM training_course_attended
GROUP BY Trunc(date_attended, 'MM')
ORDER BY Trunc(date_attended, 'MM')
Another way to generate a calendar table inline:
with calendar (month_start, month_end) as
( select add_months(date '2014-12-01', rownum)
, add_months(date '2014-12-01', rownum +1) - interval '1' second
from dual
connect by rownum <= 12 )
select to_char(c.month_start,'YYYY/MM') as course_month
, count(tca.course_attended) as attended
from calendar c
left join training_course_attended tca
on tca.date_attended between c.month_start and c.month_end
and tca.course_attended = 'Fire Safety'
group by to_char(c.month_start,'YYYY/MM')
order by 1;
(You could also have only the month start in the calendar table, and join on trunc(tca.date_attended,'MONTH') = c.month_start, though if you had indexes or partitioning on tca.date_attended that might be less efficient.)

How can I calculate a column data for different conditions using single query in sql server?

I am using below query to count a particular column data based on single condition.
SELECT COUNT(DISTINCT(S.INVOICENO)) AS LESSTWO , YEAR(S.invoicedate) YER,
Month(S.invoicedate) MNTH
FROM SALESDATA S
where S.BILLINGTYPE='INVOICE'
AND (S.invoicedate >='4-1-2009' and S.invoicedate <='4-30-2010')
AND S.TAXABLEAMT <=2000
GROUP BY YEAR(S.invoicedate) ,Month(S.invoicedate)
ORDER BY YEAR(S.invoicedate) ,Month(S.invoicedate)
But I have to calculate for 3 more conditions. Is it possible to count based on 3 conditions(i.e. 2001 - 3000,3001 - 4000, 4001 - 5000,>5000) and I want result set for all the conditions?
Regards,
N.SRIRAM
Untested, but should be about right:
SELECT CASE
WHEN S.TaxableAmt <= 2000 THEN '<=2000'
WHEN S.TaxableAmt <= 3000 THEN '2001-3000'
WHEN S.TaxableAmt <= 4000 THEN '3001-4000'
ELSE '>5000'
END as Bracket,
COUNT(DISTINCT(S.INVOICENO)) AS LESSTWO , YEAR(S.invoicedate) YER,
Month(S.invoicedate) MNTH
FROM SALESDATA S
where S.BILLINGTYPE='INVOICE'
AND (S.invoicedate >='20090401' and S.invoicedate <='20100430')
GROUP BY
CASE
WHEN S.TaxableAmt <= 2000 THEN '<=2000'
WHEN S.TaxableAmt <= 3000 THEN '2001-3000'
WHEN S.TaxableAmt <= 4000 THEN '3001-4000'
ELSE '>5000'
END,
YEAR(S.invoicedate) ,Month(S.invoicedate)
ORDER BY YEAR(S.invoicedate) ,Month(S.invoicedate)
You have to repeat the case expression in the GROUP BY clause (or put it all in a subquery), and I've fixed your date constants so that they're unambiguous.
I think you really need to split up the query into 3 distinct queries - one for each of the conditions you require