Limit to two results for each individual ID - mysql

How would I return two results for each individual meeting.id?
I've tried things like Row_Count() and Rank() but they seem to cause syntax errors.
This is my query which I need adapting to show the two results per meeting.id.
SELECT meeting_appointment.* FROM `meeting`
INNER JOIN meeting_appointment ON (
meeting_appointment.meeting_id = meeting.id AND meeting_appointment.pupil_id = 0 AND meeting_appointment.guardian_id = 0 AND meeting_appointment.deleted = 0
)
WHERE (
meeting.grade_id = "-1" OR meeting.grade_id IN ('87')
)
AND meeting.startTime < '2016-10-06 14:00:00' + INTERVAL 1 HOUR AND meeting.startTime > '2016-10-06 14:00:00' - INTERVAL 1 HOUR
GROUP by meeting_appointment.id
ORDER BY meeting_appointment.startTime ASC

If your meeting_appointment.id are consecutive then this should show the first two
meeting_appointment.id per meeting.id:
SELECT meeting_appointment.* FROM `meeting`
INNER JOIN meeting_appointment ON (meeting_appointment.meeting_id = meeting.id)
WHERE (meeting.grade_id = "-1" OR meeting.grade_id IN ('87'))
AND meeting.startTime < '2016-10-06 14:00:00' + INTERVAL 1 HOUR AND meeting.startTime > '2016-10-06 14:00:00' - INTERVAL 1 HOUR
AND meeting_appointment.pupil_id = 0
AND meeting_appointment.guardian_id = 0
AND meeting_appointment.deleted = 0
AND NOT EXISTS
(SELECT 1 FROM meeting_appointment ma WHERE ma.id<meeting_appointment.id-1
AND ma.pupil_id = 0
AND ma.guardian_id = 0
AND ma.deleted = 0
)
GROUP by meeting_appointment.id
ORDER BY meeting_appointment.startTime ASC
If you meeting_appointment.id are just random or non-numeric then it might need some tweaks but in order to code those teaks we'll need to know a bit more about the schema.

You don't have an aggregate function, so GROUP BY is redundant. Remove that, and add a LIMIT clause, and you should be good to go:
SELECT ma.*
FROM meeting m
INNER JOIN meeting_appointment ma ON ma.meeting_id = m.id
WHERE m.grade_id IN ('-1','87')
AND ma.pupil_id = 0
AND ma.guardian_id = 0
AND ma.deleted = 0
AND m.startTime < '2016-10-06 14:00:00' + INTERVAL 1 HOUR
AND m.startTime > '2016-10-06 14:00:00' - INTERVAL 1 HOUR
ORDER BY ma.startTime ASC
LIMIT 2;
You could also use BETWEEN for the datetime column.

Related

SQL how to create aggregate of two aggregated columns for each row

I'm working on a big query in SQL (MySQL 5.7) to calculate aggregated columns based on raw values in my table. I've created several aggregated columns (see attached screenshot and SQL) and I now need to create a conversion_percent column for each tlp_aff_id in my query.
This conversion_percent should be a division of the aggregated JoinedSessions.total_sessions and COUNT(Report.tlp_aff_id) as leads_total.
My current SQL:
SELECT
# Application details
Report.tlp_aff_id,
# Revenue
JoinedRevenue.total_revenue,
# Commission
JoinedCommission.total_commission,
# Profit
JoinedProfit.total_profit,
# Sessions
JoinedSessions.total_sessions,
# Submits
COUNT(Report.tlp_aff_id) as total_submits,
# Leads
COUNT(Report.tlp_aff_id) as leads_total,
SUM(case when Report.application_result = 'Accepted' then 1 else 0 end) leads_accepted,
SUM(case when Report.application_result = 'Rejected' then 1 else 0 end) leads_rejected
# Conversion percent
# JoinedConversion.conversion_percent
FROM
tlp_payout_report_minute AS Report
INNER JOIN
(
SELECT
JoinedRevenue.tlp_aff_id,
JoinedRevenue.minute_rounded_timestamp,
SUM(commission) AS total_revenue
FROM
tlp_payout_report_minute AS JoinedRevenue
WHERE
JoinedRevenue.minute_rounded_timestamp >= 1664841600
AND
JoinedRevenue.minute_rounded_timestamp <= 1664927999
GROUP BY
JoinedRevenue.tlp_aff_id
) AS JoinedRevenue
ON JoinedRevenue.tlp_aff_id = Report.tlp_aff_id
INNER JOIN
(
SELECT
ReportCommission.tlp_aff_id,
ReportCommission.seller_code,
ReportCommission.minute_rounded_timestamp,
SUM(commission) AS total_commission
FROM
tlp_payout_report_minute AS ReportCommission
WHERE
ReportCommission.minute_rounded_timestamp >= 1664841600
AND
ReportCommission.minute_rounded_timestamp <= 1664927999
AND
ReportCommission.seller_code != 44
GROUP BY
ReportCommission.tlp_aff_id
) AS JoinedCommission
ON JoinedCommission.tlp_aff_id = Report.tlp_aff_id
INNER JOIN
(
SELECT
ReportProfit.tlp_aff_id,
ReportProfit.seller_code,
ReportProfit.application_result,
ReportProfit.minute_rounded_timestamp,
SUM(commission) AS total_profit
FROM
tlp_payout_report_minute AS ReportProfit
WHERE
ReportProfit.minute_rounded_timestamp >= 1664841600
AND
ReportProfit.minute_rounded_timestamp <= 1664927999
AND
ReportProfit.application_result = 'Accepted'
AND
ReportProfit.seller_code = 44
GROUP BY
ReportProfit.tlp_aff_id
) AS JoinedProfit
ON JoinedProfit.tlp_aff_id = Report.tlp_aff_id
INNER JOIN
(
SELECT
Conversion.aff_id,
Conversion.conversion_type,
COUNT(Conversion.ip_address) as total_sessions
FROM
tlp_conversions AS Conversion
WHERE
Conversion.conversion_time >= '2022-10-04 00:00:00'
AND
Conversion.conversion_time <= '2022-10-04 23:59:59'
AND
Conversion.aff_id IS NOT NULL
AND
Conversion.conversion_type = 2
GROUP BY
Conversion.aff_id
) AS JoinedSessions
ON JoinedSessions.aff_id = Report.tlp_aff_id
WHERE
Report.minute_rounded_timestamp >= 1664841600
AND
Report.minute_rounded_timestamp <= 1664927999
GROUP BY
Report.tlp_aff_id
ORDER BY
JoinedRevenue.total_revenue DESC
I'm thinking something along the lines of:
INNER JOIN
(
...
) AS JoinedConversion
ON JoinedConversion.aff_id = Report.tlp_aff_id
But I don't think this is necessary for conversion_percent.
What's the right approach here?

Where do I begin Looping statements in MySQL Workbench

I need to have this query run 12 times (previous 12 months) and append the results to a table. I am not very good with looping, looking for input. I am just not sure where to put my counter variables or any other looping statements. I think I may need two variables to loop because of the Previous Month First Day and Last day variables.
SET #PM_FD = last_day(curdate() - interval 2 month) + interval 1 day;
SET #PM_LD = last_day(curdate() - interval 1 month);
insert into sandbox.metrics_history
SELECT
'CHI' as Company
,count(*) as Result
,'SSRM10' as Metric_ID
,'PONoReqLine' as Metric_Name
, MONTHNAME(#PM_FD) as Month, year(#PM_FD) as Year
FROM
poline pol
INNER JOIN
purchorder po ON pol.company = po.company
AND pol.po_number = po.po_number
AND pol.po_release = po.po_release
AND pol.po_code = po.po_code
LEFT JOIN
polinesrc src ON pol.company = src.company
AND pol.po_number = src.po_number
AND pol.po_release = src.po_release
AND pol.line_nbr = src.line_nbr
AND pol.po_code = src.po_code
LEFT JOIN
buyer byr ON pol.buyer_code = byr.buyer_code
WHERE
pol.buyer_code != 'POC'
AND src.company IS NULL
AND po.po_date >= #PM_FD
AND po.po_date <= #PM_LD
ORDER BY pol.company , pol.po_number , pol.line_nbr

Mysql IF statement return issues

I have this query where the IF lines are only partially returning correct result:
SELECT
COALESCE((SELECT COUNT(ID) FROM USERS_BUCKETS WHERE USERS_BUCKETS.USERID = USERS.ID),0) AS ADDED,
COALESCE((SELECT SUM(CASE WHEN USERS_BUCKETS.STATUS='Completed' THEN 1 ELSE 0 END) FROM USERS_BUCKETS WHERE USERS_BUCKETS.USERID = USERS.ID),0) AS DONE,
COALESCE((SELECT COUNT(ID) FROM USERS_LIKES WHERE USERS_LIKES.USERID = USERS.ID),0) AS NUM_LIKES,
COALESCE((SELECT COUNT(ID) FROM FOLLOW WHERE FOLLOW.USER_ID=USERS.ID),0) AS FOLLOWING,
COALESCE((SELECT COUNT(ID) FROM FOLLOW WHERE FOLLOW.FOLLOW_ID=USERS.ID),0) AS FOLLOWERS,
(SELECT IF(ADDED >= 5,1,0)) AS IFADDED,
(SELECT IF(DONE >= 3,1,0)) AS IFDONE,
(SELECT IF(NUM_LIKES >= 5,1,0)) AS IFNUM_LIKES,
(SELECT IF(FOLLOWING >= 5,1,0)) AS IFFOLLOWING,
(SELECT IF(FOLLOWERS >= 3,1,0)) AS IFFOLLOWERS,
(SELECT IF(ADDED >= 5,1,0) + IF(DONE >= 3,1,0) + IF(NUM_LIKES >= 5,1,0) + IF(FOLLOWING >= 5,1,0) + IF(FOLLOWERS >= 3,1,0)) AS PROGRESS
FROM USERS
WHERE USERS.ID=?
Result:
ADDED: 20
IFADDED: 1
DONE: 9
IFDONE: 0 //should be 1
NUM_LIKES: 11
IFNUM_LIKES: 1
FOLLOWING: 11
IFFOLLOWING: 0 //should be 1
FOLLOWERS: 10
IFFOLLOWERS: 0 //should be 1
PROGRESS: 2
What's wrong? All IF values should be 1 and PROGRESS should be 5.
Note: I am using PDO in php, but I don't think that matters at all.
I have no idea why your code is working. The columns are definitely not the column aliases defined earlier in the query.
To do what you want, use a subquery and simplify the logic:
SELECT u.*, (ADDED >= 5) AS IFADDED,
(DONE >= 3) AS IFDONE,
(NUM_LIKES >= 5) AS IFNUM_LIKES,
(FOLLOWING >= 5) AS IFFOLLOWING,
(FOLLOWERS >= 3) AS IFFOLLOWERS,
((ADDED >= 5) + (DONE >= 3) + (NUM_LIKES >= 5) + (FOLLOWING >= 5) +
(FOLLOWERS >= 3)
) AS PROGRESS
FROM (SELECT COALESCE((SELECT COUNT(ID) FROM USERS_BUCKETS WHERE USERS_BUCKETS.USERID = USERS.ID),0) AS ADDED,
COALESCE((SELECT SUM(CASE WHEN USERS_BUCKETS.STATUS='Completed' THEN 1 ELSE 0 END) FROM USERS_BUCKETS WHERE USERS_BUCKETS.USERID = USERS.ID),0) AS DONE,
COALESCE((SELECT COUNT(ID) FROM USERS_LIKES WHERE USERS_LIKES.USERID = USERS.ID),0) AS NUM_LIKES,
COALESCE((SELECT COUNT(ID) FROM FOLLOW WHERE FOLLOW.USER_ID=USERS.ID),0) AS FOLLOWING,
COALESCE((SELECT COUNT(ID) FROM FOLLOW WHERE FOLLOW.FOLLOW_ID=USERS.ID),0) AS FOLLOWERS
FROM USERS
WHERE USERS.ID = ?
) u;
This takes advantage of the fact that MySQL treats booleans as integers in a numeric context, with "1" for true and "0" for false.
EDIT: I should also note that the coalesce() is unnecessary because count() will return 0 when there are no matches.

how to get SUM() of COUNT() column in MySQL

i have the following query, tried using case statement
SELECT t.inst_id, t.inst_username, tcm.city_name,
SUM(CASE WHEN psb.pms_student_bucket_id IS NULL THEN 1 ELSE 0 END) AS not_assiged,
SUM(CASE WHEN COUNT(psb.pms_student_bucket_id) BETWEEN 1 AND 50 THEN 1 ELSE 0 END) AS '1-50',
SUM(CASE WHEN COUNT(psb.pms_student_bucket_id) > 50 THEN 1 ELSE 0 END) AS ' > 50'
FROM tbl_si_di t
JOIN tbl_city_master tcm ON tcm.city_id = t.city_ref_id
JOIN tbl_si_students tss ON tss.inst_ref_id = t.inst_id
LEFT JOIN pms_student_bucket psb ON psb.user_ref_id = tss.user_ref_id
GROUP BY t.inst_id;
I need SUM of pms_student_bucket_id column when their COUNT is '1-50' and '>50'. Right now this query is saying Invalid use of group function.
How would I SUM on COUNT of "pms_student_bucket_id" equals/between some value in mysql?
you could put it in a subquery
SELECT inst_id, inst_username, city_name,
SUM(pms_student_bucket_id IS NULL ) AS not_assiged,
SUM(num_bucket >=10 AND num_bucket <= 20) AS '10 - 20'
SUM(num_bucket <= 50) AS '1-50',
SUM(num_bucket > 50) AS ' > 50'
FROM
( SELECT t.inst_id, t.inst_username, tcm.city_name,psb.pms_student_bucket_id,
COUNT(psb.pms_student_bucket_id) as num_bucket
FROM tbl_si_di t
JOIN tbl_city_master tcm ON tcm.city_id = t.city_ref_id
JOIN tbl_si_students tss ON tss.inst_ref_id = t.inst_id
LEFT JOIN pms_student_bucket psb ON psb.user_ref_id = tss.user_ref_id
GROUP BY t.inst_id
)t1
GROUP BY inst_id;
note you can use the boolean values returned to do what you want.. aka you don't need a case statement, the boolean value returns a 1 or 0 which can then be summed..

SQL Server 2008 left join where clause based on max date

Got some help the other day on this and now really want to make a change for the better
Here is code
select
machines.serialnum, DRPS.assetnumber, DRPS.MOCALCSUM, DRPS.MICALCSUM,
DRPS.COCALCSUM, DRPS.CICALCSUM, ISSUED.TotalIssued,
REDEEMED.TotalRedeemed,drps.dropdate1,drps.dropdate2
from
(select serialnum
from machineinfo) as machines
LEFT JOIN
(select
assetnumber, min(dropdate) as [dropdate1], max(dropdate) as [dropdate2],
sum(mocalc) AS [MOCALCSUM], sum(micalc) AS [MICALCSUM],
sum(cocalc) AS [COCALCSUM],sum(cicalc) AS [CICALCSUM]
from drops
where dropdate > '09/04/2012' and dropdate < dateadd(hour, -0, getdate())
GROUP BY assetnumber) AS DRPS on machines.serialnum = drps.assetnumber
LEFT JOIN
(select
snissued, cast(sum(amount) as money) / 100 AS [TotalIssued]
from tickets
where dateissued > '09/04/2012' and dateissued < dateadd(hour, 0, getdate())
group by snissued) AS ISSUED ON machines.serialnum = ISSUED.snissued
LEFT JOIN
(select
snredeemed, cast(sum(amount) as money) / 100 AS [TotalRedeemed]
from tickets
where dateredeemed > '09/04/2012' and dateredeemed < dateadd(hour, 0, getdate())
group by snredeemed) AS REDEEMED ON machines.serialnum = REDEEMED.snredeemed
what I would like to accomplish if possible is for the second and third join is to use the drps.drop1 in the where clause like this
where dropdate > drps.dropdate1 and dropdate < drps.dropdate2
but it does not work
here is working output
serialnum MOCALCSUM MICALCSUM COCALCSUM CICALCSUM TotalIssued TotalRedeemed dropdate1 dropdate2
0-2739-41401 5482 5498 132 148 3258.00 3110.00 2012-09-04 13:36:53.450 2012-09-05 13:55:38.750
0-2459-36182 1110 1054 114 58 1895.00 1657.00 2012-09-04 15:01:19.973 2012-09-05 13:55:38.967
end result is I need total issued and total redeemed date range to be between the min and max date per serial number
declare #datebegin datetime
declare #dateend datetime
set #datebegin = '09/04/2012'
set #dateend = '09/08/2012'
select machines.serialnum, DRPS.MOCALCSUM,DRPS.MICALCSUM,DRPS.COCALCSUM,DRPS.CICALCSUM,ISSUED.TotalIssued,
REDEEMED.TotalRedeemed,drps.dropdate1,drps.dropdate2
from (select serialnum
from machineinfo) as machines
LEFT JOIN (select assetnumber,min(dropdate)as [dropdate1], max(dropdate)as [dropdate2], sum(mocalc) AS [MOCALCSUM],sum(micalc) AS [MICALCSUM],
sum(cocalc) AS [COCALCSUM],sum(cicalc) AS [CICALCSUM]
from drops
where dropdate > #datebegin and dropdate < #dateend AND (ignore is null)
group by assetnumber) AS DRPS
on machines.serialnum = drps.assetnumber
LEFT JOIN (select snissued,cast(sum(amount)as money)/100 AS [TotalIssued] from tickets
where (dateissued > (select min(dropdate)
from drops
where dropdate > #datebegin AND (ignore is null) and snissued = assetnumber ))
and
(dateissued < (select max(dropdate)
from drops
where dropdate < #dateend AND (ignore is null) and snissued = assetnumber))
group by snissued) AS ISSUED
ON machines.serialnum=ISSUED.snissued
LEFT JOIN (select snredeemed,cast(sum(amount)as money)/100 AS [TotalRedeemed]
from tickets
where (dateredeemed > (select min(dropdate)
from drops
where dropdate > #datebegin AND (ignore is null)and snissued = assetnumber))
and
(dateredeemed < (select max(dropdate)
from drops
where dropdate < #dateend AND (ignore is null)and snissued = assetnumber ))
group by snredeemed) AS REDEEMED
ON machines.serialnum=REDEEMED.snredeemed
order by REDEEMED.TotalRedeemed desc
based on the suggestion from comments i added the subquery into the selects and i am getting expected results now