SQL - Calculate Incentive using Frequency (Mode) - sql

I’d like a SQL query to calculate the incentive column and based on the number of times a student was tutored in a month.
If the student was tutored in AP Math twice in a month then, the Tutor gets $20, else $0.
I don’t want group the date into month summary so, I’d like to leave the dates as is hence why I assigned $10 for each record where the students that were tutored twice in month.

I think you just need window functions:
select t.*,
(case when cnt = 2 then 10 else 0 end) as incentive
from (select t.*,
count(*) over (partition by studentid, subject, tutor, year(studentvisitdate), month(studentvisitdate) as cnt
from t
) t

initializing the data
declare #StudentTable as table
(
StudentVisitDate date,
StudentId int,
StudentName varchar(100),
[Subject] varchar (30),
Tutor varchar(100),
Incentive int
)
insert into #StudentTable
values
('2018-August-03',123,'Terry Brooks','AP Math','Shawn Green',10)
,('2018-August-04',123,'Terry Brooks','AP Science','Ted Berry',10)
,('2018-August-07',123,'Terry Brooks','Music','Shawn Green',10)
,('2018-September-03',123,'Terry Brooks','AP Math','Shawn Green',10)
,('2018-September-04',123,'Terry Brooks','AP Science','Ted Berry',10)
,('2018-September-07',123,'Terry Brooks','AP Math','Shawn Green',10)
getting the count of visits per month, grouping the data
;with temp as
(
select
StudentId, Subject, Tutor,Month(StudentVisitDate) [month]
,max(StudentVisitDate) maxdate -- the date on which the incentive will be calculated
,Count(StudentVisitDate) [count]
from #StudentTable
Group by
StudentId, Subject, Tutor,Month(StudentVisitDate)
)
getting the effective incentives for each month using the information from above table
select
s.StudentVisitDate ,
s.StudentId ,
s.StudentName ,
s.[Subject] ,
s.Tutor ,
Case
when t.maxdate = s.StudentVisitDate -- the incentive will be applied on the maximum date
then
s.Incentive*t.count
else
0
end Incentive
from #StudentTable s
inner join temp t
on s.StudentId=t.StudentId
and s.Subject =t.Subject
and s.Tutor=t.Tutor
and Month(s.StudentVisitDate)=t.month
order by StudentVisitDate
Final output -
StudentVisitDate StudentId StudentName Subject Tutor Incentive
2018-08-03 123 Terry Brooks AP Math Shawn Green 10
2018-08-04 123 Terry Brooks AP Science Ted Berry 10
2018-08-07 123 Terry Brooks Music Shawn Green 10
2018-09-03 123 Terry Brooks AP Math Shawn Green 0
2018-09-04 123 Terry Brooks AP Science Ted Berry 10
2018-09-07 123 Terry Brooks AP Math Shawn Green 20

Related

Find the Age and Name of the Youngest Player for Each Race

Table "participant":
ptcpt_id
ptcpt_name
brt_dt
1
Ana Perez
2001-10-10
2
John Sy
1999-04-03
3
Judy Ann
2001-10-10
Table "race":
race_id
race_name
race_date
1
Vroom Vroom
2023-01-01
2
Fast & Furious
2022-01-01
Table "individual_race_record":
irr_id
ptcpt_id
race_id
run_time
1
1
1
00:59:13
2
1
2
01:19:14
3
2
1
00:48:05
4
2
2
01:01:17
5
3
2
01:31:18
I want to select the name and age of the youngest participant for each race event, as well as the name and year of each race event.
This is what I have so far:
SELECT
r.race_name,
EXTRACT(YEAR FROM r.race_date) AS year,
COALESCE(CAST(min.age AS varchar), 'N/A')
FROM(
SELECT
race_id,
EXTRACT(YEAR FROM MIN(AGE(brt_dt))) AS age
FROM(
SELECT p.ptcpt_id, p.brt_dt, irr.race_id
FROM participant p
INNER JOIN individual_race_record irr
ON p.ptcpt_id = irr.ptcpt_id
) sub
GROUP BY race_id
) min
RIGHT JOIN race r ON r.race_id=min.race_id
ORDER BY year DESC
which resulted to the following table:
race_name
year
age
Vroom Vroom
2023
21
Fast & Furious
2022
21
But what I want is this:
race_name
year
age
ptcpt_name
Vroom Vroom
2023
21
Ana Perez
Fast & Furious
2022
21
Ana Perez
Fast & Furious
2022
21
Judy Ann
The problem is that I can't join it with the participant table. I still need another column for the name of the youngest participant. And if there are multiple youngest participant in a race, I'd like to show them both. When I try to select the ptcpt_id for the 'min' table it resulted to an error saying that I have to also include the ptcpt_id under the GROUP BY function. But I don't need it to be grouped by participants.
I'd appreciate any help and leads on this issue. Thank you.
You can use FETCH FIRST ROWS WITH TIES to gather all records that tie on the first ORDER BY field. Namely, if we use DENSE_RANK to assign a ranking to each person for each race, based on their age, it will allow to get all people with minimum age for each race. Since we're using DENSE_RANK, it will retrieve all people having the minimum age, if there's more than one.
SELECT r.race_name,
EXTRACT(YEAR FROM r.race_date) AS "year",
DATE_PART('year', r.race_date) - DATE_PART('year', p.brt_dt) AS age,
p.ptcpt_name
FROM participant p
INNER JOIN individual_race_record irr ON p.ptcpt_id = irr.ptcpt_id
INNER JOIN race r ON r.race_id = irr.race_id
ORDER BY DENSE_RANK() OVER(
PARTITION BY race_name
ORDER BY DATE_PART('year', r.race_date) - DATE_PART('year', p.brt_dt))
FETCH FIRST 1 ROWS WITH TIES
Output:
race_name
year
age
ptcpt_name
Fast & Furious
2022
21
Ana Perez
Fast & Furious
2022
21
Judy Ann
Vroom Vroom
2023
22
Ana Perez
Check the demo here.

SQL COUNT the number purchase between his first purchase and the follow 10 months

every customer has different first-time purchase date, I want to COUNT the number of purchases they have between the following 10 months after the first purchase?
sample table
TransactionID Client_name PurchaseDate Revenue
11 John Lee 10/13/2014 327
12 John Lee 9/15/2015 873
13 John Lee 11/29/2015 1,938
14 Rebort Jo 8/18/2013 722
15 Rebort Jo 5/21/2014 525
16 Rebort Jo 2/4/2015 455
17 Rebort Jo 3/20/2016 599
18 Tina Pe 10/8/2014 213
19 Tina Pe 6/10/2016 3,494
20 Tina Pe 8/9/2016 411
my code below just use ROW_NUM function to identify the first purchase, but I don't know how to do the calculations or there's a better way to do it?
SELECT client_name,
purchasedate,
Dateadd(month, 10, purchasedate) TenMonth,
Row_number()
OVER (
partition BY client_name
ORDER BY client_name) RM
FROM mytable
You might try something like this - I assume you're using SQL Server from the presence of DATEADD() and the fact that you're using a window function (ROW_NUMBER()):
WITH myCTE AS (
SELECT TransactionID, Client_name, PurchaseDate, Revenue
, MIN(PurchaseDate) OVER ( PARTITION BY Client_name ) AS min_PurchaseDate
FROM myTable
)
SELECT Client_name, COUNT(*)
FROM myCTE
WHERE PurchaseDate <= DATEADD(month, 10, min_PurchaseDate)
GROUP BY Client_name
Here I'm creating a common table expression (CTE) with all the data, including the date of first purchase, then I grab a count of all the purchases within a 10-month timeframe.
Hope this helps.
Give this a whirl ... Subquery to get the min purchase date, then LEFT JOIN to the main table to have a WHERE clause for the ten month date range, then count.
SELECT Client_name, COUNT(mt.PurchaseDate) as PurchaseCountFirstTenMonths
FROM myTable mt
LEFT JOIN (
SELECT Client_name, MIN(PurchaseDate) as MinPurchaseDate GROUP BY Client_name) mtmin
ON mt.Client_name = mtmin.Client_name AND mt.PurchaseDate = mtmin.MinPurchaseDate
WHERE mt.PurchaseDate >= mtmin.MinPurchaseDate AND mt.PurchaseDate <= DATEADD(month, 10, mtmin.MinPurchaseDate)
GROUP BY Client_name
ORDER BY Client_name
btw I'm guessing there's some kind of ClientID involved, as nine character full name runs the risk of duplicates.

Advanced Sql query solution required

player team start_date end_date points
John Jacob SportsBallers 2015-01-01 2015-03-31 100
John Jacob SportsKings 2015-04-01 2015-12-01 115
Joe Smith PointScorers 2014-01-01 2016-12-31 125
Bill Johnson SportsKings 2015-01-01 2015-06-31 175
Bill Johnson AllStarTeam 2015-07-01 2016-12-31 200
The above table has many more rows. I was asked the below questions in an interview.
1.)For each player, which team were they play for on 2015-01-01?
I could not answer this one.
2.)For each player, how can we get the team for whom they scored the most points?
select team from Players
where points in (select max(points) from players group by player).
Please, solutions for both.
1
select *
from PlayerTeams
where startdate <='2015-01-01' and enddate >= '2015-01-01'
2
Select player, team, points
from(
Select *, row_number() over (partition by player order by points desc) as rank
From PlayerTeams) as player
where rank = 1
For #1:
Select Player
,Team
From table
Where '2015-01-01' between start_date and end_date
For #2:
select t.Player
,t.Team
from table t
inner join (select Player
,Max(points)
from table
group by Player) m
on t.Player = m.Player
and t.points = m.points

Select from two tables and set null column

I have two tables
Schedule:
scheduleID DriverID ScheduleDate
11 1 2015-05-20
22 2 2015-05-20
33 NULL 2015-05-21
44 NULL 2015-05-21
and
Employee:
ID Fname Lname
1 jack miller
2 kelly moore
3 mark sam
4 tom hanks
I want to select from these two tables based on ScheduleDate and show the driver full name from Employee table and show null columns.
The result should be like:
scheduleID Fname Lname
33 NULL NULL
44 NULL NULL
I used:
select row_number() over (order by scheduleID desc) as schedule, scheduleID, Driver_ID,FirstName,LastName
From Schedule, Employee
where scheduleDate= '2015-05-21' AND EmployeID=Driver_ID;
It works well if " scheduleDate= '2015-05-20' "
but I need to show null Columns too!
any help!
You need a left join for this -- just emphasizing why you should never using implicit join syntax. Simple rule: Always use explicit join syntax. Never use commas in the from clause.
select row_number() over (order by scheduleID desc) as schedule, scheduleID,
Driver_ID, FirstName, LastName
From Schedule left join
Employee
on EmployeID = Driver_ID
where scheduleDate = '2015-05-21';

How to get the student academic progress?

course Table
course_code course_name credit_points_reqd
1 Comp Science 300
2 Soft Engineering 300
subject Table
subject_code subject_name credit_points
CS123 C Prog 15
CS124 COBOL 15
enrolment table
student_id student_name course_code subject_code Results
1 Lara Croft 1 CS123 70
1 Lara Croft 1 CS124 50
2 Tom Raider 2 CS123 60
2 Tom Raider 2 CS124 40
3 James Bond 1 CS123 NULL
3 James Bond 1 CS124 40
OUTPUT TABLE
student_name course_name credit_points_obt credit_points_reqd
Lara Croft Comp Science 30 300
Tom Raider Soft Engineering 15 300
I'm currently using TSQL. So here's the situation. I've prepared these tables to get the output like the way it i showed u up there. I need to calculate the credit points obtained. Credit points are achieved if the student receives > 50 for a subject they took. I want to ignore students that has not received any credit points at all (eg, James Bond is ignored as he has not achieved any points yet)
select student_name, course_name,credit_points_obt,credit_points_reqd
FROM enrolment (SELECT student_full_name, SUM(credit_points) AS credit_points_obt
FROM enrolment
GROUP BY student_id),
Totally stuck...I have no idea where to go now.
You can sum conditionally to get points for subject. If none are given result will be null, so you filter out those student/course pairs in having clause.
I've changed > 50 condition to >= 50 because your results contradict your requirements. Also, by the data I'd say that you have omitted student table for brewity, but if you haven't, it is a must.
Live test is # Sql Fiddle.
select enrolment.student_name,
course.course_name,
course.credit_points_reqd,
sum(case when enrolment.results >= 50
then subject.credit_points
end) credit_points_obt
FROM enrolment
inner join course
on enrolment.course_code = course.course_code
inner join subject
on enrolment.subject_code = subject.subject_code
group by enrolment.student_name,
course.course_name,
course.credit_points_reqd
having sum(case when enrolment.results >= 50
then subject.credit_points
end) is not null