SQL - Divide One Query by Another - mysql

I am trying to create a query which returns the workout percentage completion...
Workout Percentage Completion =
((Sum of LogEntries WHERE date = IN list of dates and WorkoutID =1 ) /
(Sum of all set numbers WHERE WorkoutID = 1))
x 100
Below is what I currently have, at the moment it is only returning the result of the first query.
What should I change for the query to run correctly?
SELECT
(
(
SELECT COUNT(LogEntriesID)
FROM LogEntriesTable
LEFT JOIN ExerciseWorkoutJunctionTable
ON ExerciseWorkoutJunctionTable.ExerciseWorkoutJunctionID =
LogEntriesTable.JunctionID
WHERE LogEntriesTable.date IN (
"14-05-2020", "15-05-2020", "16-05-2020", "17-05-2020",
"18-05-2020", "19-05-2020", "20-05-2020"
)
AND ExerciseWorkoutJunctionTable.WorkoutID = 1
) / (
SELECT sum(SetNumber)
FROM ExerciseWorkoutGoalsTable
LEFT JOIN ExerciseWorkoutJunctionTable
ON ExerciseWorkoutJunctionTable.ExerciseWorkoutJunctionID =
ExerciseWorkoutGoalsTable.JunctionID
WHERE ExerciseWorkoutJunctionTable.WorkoutID = 1
)
)

Your first SELECT statement is doing an OUTER JOIN but then you have a WHERE clause that is selecting non-NULL values from the ExerciseWorkoutJunctionTable table, so I suspect you might as well be doing an INNER JOIN.
When you have two queries, try:
SET #sum = (SELECT SUM(SetNumber) etc ....);
SELECT (COUNT(LogEntriesID) * 100 / #sum) AS percentage
FROM etc.

If you are using MySQL >= 8.0 you should be able to use window functions like this which breakdown your query into more readable sections.
with entries as (
SELECT COUNT(LogEntriesID) as log_entry_count
FROM LogEntriesTable as l
LEFT JOIN ExerciseWorkoutJunctionTable as e ON
e.ExerciseWorkoutJunctionID = l.JunctionID
WHERE l.date IN ("14-05-2020","15-05-2020","16-05-2020","17-05-2020","18-05-2020","19-05-2020","20-05-2020")
AND e.WorkoutID = 1
),
sets as (
SELECT sum(SetNumber) as set_sum
FROM ExerciseWorkoutGoalsTable as eg
LEFT JOIN ExerciseWorkoutJunctionTable ej
ON ej.ExerciseWorkoutJunctionID = eg.JunctionID
WHERE ej.WorkoutID = 1
)
select ((select log_entry_count from entries) / (select set_sum from sets)) * 100 as workout_completion_pct

Related

I have a somewhat complex SQL statement, but I don't know where to put the WHERE clause

I don't know where to put the WHERE clause. In the driverstops table, I have a field called delivdate, and the table damagelog has a field called dateofdelivery. I want to specify specific date ranges. Where can I put the WHERE clause to limit the data?
SELECT
dr.drivername,
sumStops,
perfectcnt/sumStops * 100 AS perfpcnt,
qualcnt/sumStops * 100 AS qualpcnt,
compcnt/sumStops * 100 As comppcnt,
damacnt/sumStops * 100 AS damapcnt,
nofitcnt/sumStops * 100 AS nofitpcnt,
incocnt/sumStops * 100 AS incopcnt,
misscnt/sumStops * 100 AS misspcnt,
notlcnt/sumStops * 100 AS notlpcnt,
noupcnt/sumStops * 100 AS nouppcnt,
failccnt/sumStops * 100 AS failcpcnt,
failscnt/sumStops * 100 AS failspcnt,
conccnt/sumStops * 100 AS concpcnt,
nocodcnt/sumStops * 100 AS nocodpcnt,
failicnt/sumStops * 100 AS failipcnt
FROM drivers dr
LEFT JOIN (
SELECT
driverid,
SUM(numberofstops) sumStops
FROM driverstops
GROUP BY driverid
) stops ON dr.id = stops.driverid
LEFT JOIN (
SELECT
driverid,
damagelog.dateofdelivery date,
SUM(perfect) perfectcnt,
SUM(quality) qualcnt,
SUM(compliment) compcnt,
SUM(damage) damacnt,
SUM(nofit) nofitcnt,
SUM(incomplete) incocnt,
SUM(misseddeliv) misscnt,
SUM(notloaded) notlcnt,
SUM(noupdate) noupcnt,
SUM(failcall) failccnt,
SUM(failsendemail) failscnt,
SUM(concerns) conccnt,
SUM(nocod) nocodcnt,
SUM(failinst) failicnt
FROM damagelog
GROUP BY driverid
) dam ON dr.id = dam.driverid
As far as concerns, the columns that you want to filter on come from aggregated subqueries that are then JOINed. There is one join (driverstops) where the field you want to filter on is not returned by the subquery.
It seems like the simplest solution is to put a WHERE clause in each subquery, like :
LEFT JOIN (
SELECT driverid,SUM(numberofstops) sumStops
FROM driverstops
WHERE delivdate BETWEEN #stat_date AND #end_date
GROUP BY driverid
) stops ON dr.id = stops.driverid
And :
LEFT JOIN (
SELECT
driverid,
damagelog.dateofdelivery date,
SUM(perfect) perfectcnt,
...
FROM damagelog
WHERE dateofdelivery BETWEEN #stat_date AND #end_date
GROUP BY driverid
) dam ON dr.id = dam.driverid

How to update a table with subquery using data from the same table

I would like to update a column from a table, and the data i want to put in is the result of a mathematical operation using subquerys that references the update table.
The problem is I want to update every row using data from the same row in the mathematical operation mentioned above.
Here's the example:
UPDATE licenses as lic
SET lic.numSessions =
(
select difference from
(select
(
select (p.numSessions * p.numMonth) as num from products p
inner join licenses l on p.idProduct = l.idProduct and l.idpatient = lic.idPatient and l.currentLicense = 1
)
-
(
SELECT COUNT(distinct s.idSession) as num
FROM sessions s
WHERE s.idPatient = lic.idPatient
AND s.dateValue >= (select l.dateCreated from licenses l where l.idPatient = lic.idPatient and l.currentLicense = 1) AND s.status = 2
)
as difference
)
x
);
EDIT:
Example of what i want:
Every row of 'licenses' has a 'idPatient'. Let's call it 'X'.
I want to see how many sessions X has done (for example 10) and then substract this number from the total number of sessions of 'X's' product have (for example 50). So the result in the update for X will be: 50 - 10 = 40.
The subqueries alone work perfectly, I'have the value of 50, then the value of 10, and then when I try to substract I have the value 40 as a column named 'difference'.
The problem I've got is that the query can't recognize the value 'lic.idPatient' inside the first subquery in the substract operation:
/* SQL Error (1054): Unknown column 'lic.idPatient' in 'on clause' */
Thanks in advance and sorry for my writing, I'm not native English.
You have to write query like this
UPDATE licenses AS licNew
SET licNew.numSessions =
(
SELECT x.difference FROM
((SELECT
(
SELECT (p.numSessions * p.numMonth) AS num FROM products p
INNER JOIN licenses l ON p.idProduct = l.idProduct AND l.idpatient = lic.idPatient AND l.currentLicense = 1
)
-
(
SELECT COUNT(DISTINCT s.idSession) AS num
FROM sessions s
WHERE s.idPatient = 6361
AND s.dateValue >= (SELECT l.dateCreated FROM licenses l WHERE l.idPatient = 6361 AND l.currentLicense = 1) AND s.status = 2
))
AS difference, lic.idPatient
FROM licenses lic
)
X WHERE licNew.idPatient = x.idPatient
);
In general, you cannot modify a table and select from the same table in a subquery.
Please refer this link.

which is the best / efficient way to execute MySQL query

1st approach :-
SELECT
clipComment.commentId,
clipComment.commentedBy,
clipComment.clipId AS commentTypeId,
'clip' AS commentType,
clipComment.commentDescription,
clipComment.commentCreatedDateTime,
clipComment.commentModifiedDateTime,
clipComment.commentLikeCount,
userProfile.userName,
userProfile.firstName,
userProfile.LastName,
userProfile.profilePicUrl,
userProfile.themeForeground,
userProfile.themeBackground,
IF(derCommentLike.commentId = clipComment.commentId,
1,
0) likedByMe
FROM
clipComment
LEFT JOIN
(SELECT
*
FROM
clipCommentLikes
WHERE
commentLikedBy = 16) derCommentLike
ON
derCommentLike.commentId = clipComment.commentId
LEFT JOIN
userProfile
ON
userProfile.userId = clipComment.commentedBy
WHERE
clipComment.clipId = 141
2nd approach :-
SELECT
clipComment.commentId,
clipComment.commentedBy,
clipComment.clipId AS commentTypeId,
'clip' AS commentType,
clipComment.commentDescription,
clipComment.commentCreatedDateTime,
clipComment.commentModifiedDateTime,
clipComment.commentLikeCount,
userProfile.userName,
userProfile.firstName,
userProfile.LastName,
userProfile.profilePicUrl,
userProfile.themeForeground,
userProfile.themeBackground,
IF( derCommentLike.commentId = clipComment.commentId , 1 , 0 ) AS likedByMe
FROM
(SELECT
*
FROM
clipCommentLikes
WHERE
commentLikedBy = 16) derCommentLike
RIGHT OUTER JOIN clipComment
ON derCommentLike.commentId = clipComment.commentId
RIGHT OUTER JOIN userProfile
ON clipComment.commentedBy = userProfile.userId
WHERE
clipComment.clipId = 141
both query returns same result, but just want to know which approach should i follow & which one is more efficient to follow. record set will contain millions of record, so i want to use best way. or i am doing work then please correct me. thank you in advance.
explain statement 1st approach
explain statement 2nd approach
explain statement 1st approach
IF(derCommentLike.commentId = clipComment.commentId, 1, 0) likedByMe
...
LEFT JOIN
(SELECT *
FROM clipCommentLikes
WHERE commentLikedBy = 16
) derCommentLike
ON derCommentLike.commentId = clipComment.commentId
-->
( EXISTS SELECT * FROM clipCommentLikes
WHERE commentId = clipComment.commentId
) AS likedByMe
Explanation:
JOIN ( SELECT ... ) has no index to make it efficient
LEFT JOIN ( ... ) begs for evaluating the subquery after the left table, thereby begging for the subquery to be evaluated repeatedly.
SELECT * (in your subquery) is gathering lots of stuff that is not used. (SELECT * in EXISTS does not mean to fetch everything; the * is just a place holder.)
EXISTS evaluates to 1 (true) or 0 (false), which seems to be what you want.

What is the effect of performance of a SQL query when have aggregate function and where clause

I have 2 queries :
1.
SELECT u.unitId unitId,
u.unitScode 'unitScode',
( Cast(Count(vd.Date) AS FLOAT) / u.timeDiff ) * 100 'BookingCount',
u.tradeStartTime,
u.tradeStopTime,
u.minimumSlot,
u.maximumTerm
FROM #allDates vd
INNER JOIN CommcmlBookingDetail cd
ON vd.Date BETWEEN cd.dtFromTime AND cd.dtToTime
AND Datepart(minute, vd.date) = Datepart(minute, cd.dtFromTime)
INNER JOIN CommCmlBooking cb
ON cb.hMy = cd.hBooking
AND cb.iStatus = 1
AND cb.iType = 525
INNER JOIN #unitsInfo u
ON u.unitId = cb.hUnit
AND Cast(vd.Date AS DATE) BETWEEN Cast(#BookingFromDate AS DATE) AND Cast(#BookingToDate AS DATE)
AND Cast(vd.Date AS TIME) BETWEEN Cast(u.tradeStartTime AS TIME) AND Cast(u.tradeStopTime AS TIME)
WHERE cb.hRecord = case when #amendmentId = 0 then cb.hRecord else #amendmentId end
GROUP BY u.unitId,
u.unitScode,
u.minimumSlot,
u.tradeStartTime,
u.timeDiff,
u.tradeStopTime,
u.maximumTerm;
2.
INSERT INTO #tempBookingCount
SELECT u.unitId,
u.timeDiff
FROM #allDates vd
INNER JOIN CommcmlBookingDetail cd
ON vd.Date BETWEEN cd.dtFromTime AND cd.dtToTime
AND Datepart(minute, vd.date) = Datepart(minute, cd.dtFromTime)
INNER JOIN CommCmlBooking cb
ON cb.hMy = cd.hBooking
AND cb.iStatus = 1
AND cb.iType = 525
INNER JOIN #unitsInfo u
ON u.unitId = cb.hUnit
AND Cast(vd.Date AS DATE) BETWEEN Cast(#BookingFromDate AS DATE) AND Cast(#BookingToDate AS DATE)
AND Cast(vd.Date AS TIME) BETWEEN Cast(u.tradeStartTime AS TIME) AND Cast(u.tradeStopTime AS TIME)
WHERE cb.hRecord = case when #amendmentId = 0 then cb.hRecord else #amendmentId end
INSERT INTO #unitBookingCount
SELECT tt.unitID,
u.unitScode,
( Cast(Count(tt.unitID) AS FLOAT) / tt.timeDiff ) * 100,
u.tradeStartTime,
u.tradeStopTime,
u.minimumSlot,
u.maximumTerm
FROM #tempBookingCount tt
INNER JOIN #unitsInfo u
ON u.unitId = tt.unitID
GROUP BY tt.unitID,
tt.timeDiff,
u.tradeStartTime,
u.tradeStopTime,
u.minimumSlot,
u.maximumTerm,
u.unitScode
I have separated the first query into 2 parts, and i can a huge difference in the performance!
The first query take 14 seconds when executed for 5 months where as next query take 4 seconds.
Your original query uses 2 table variables #allDates and #unitsInfo.
By using table variables, you aren't giving SQL a fighting chance of optimizing the query because there are no statistics on table variables and the row count estimations and query plan are impacted.
One reference, you can find many more:
http://blogs.msdn.com/b/psssql/archive/2010/08/24/query-performance-and-table-variables.aspx
Try the original with #TempTables instead of #TableVars

SQL Query behavior

I'm bogged in trying to figure out why query a is returning different records than query b. Both queries have seemingly same purpose yet a is returning 500 and b 3500.
this is query a:
SELECT DISTINCT ODE.OrderBillToID
FROM APTIFY.dbo.vwVwOrderDetailsKGExtended ODE
WHERE ProductID IN (2022, 1393)
AND LTRIM(RTRIM(ODE.OrderStatus)) <> 'Cancelled'
AND LTRIM(RTRIM(ODE.OrderType)) <> 'Cancellation'
AND LTRIM(RTRIM(ODE.cancellationStatus)) <> 'FULLY CANCELLED'
UNION
SELECT DISTINCT ID
FROM APTIFY.dbo.vwPersons WHERE City = 'A'
UNION
SELECT DISTINCT RecordID
FROM APTIFY.dbo.vwTopicCodeLinks WHERE TopicCodeID = 16 AND Value = 'Yes, Please'
query b:
SELECT
APTIFY..vwPersons.ID
FROM
APTIFY..vwPersons
WHERE
( APTIFY..vwPersons.ID IN (
SELECT
vwMeetingRegistrants.ID
FROM
APTIFY.dbo.vwMeetings vwMeetings
INNER JOIN APTIFY.dbo.vwMeetingRegistrants vwMeetingRegistrants
ON vwMeetings.ID=vwMeetingRegistrants.ActualMeetingID WHERE
vwMeetings.ProductID = 2022
)
OR
APTIFY..vwPersons.ID IN (
SELECT
vwMeetingRegistrants.ID
FROM
APTIFY.dbo.vwMeetings vwMeetings
INNER JOIN APTIFY.dbo.vwMeetingRegistrants vwMeetingRegistrants
ON vwMeetings.ID=vwMeetingRegistrants.ActualMeetingID WHERE
vwMeetings.ProductID = 1393
)
OR
APTIFY..vwPersons.City = N'Albany' )
OR
((
APTIFY..vwPersons.ID IN (
SELECT
RecordID
FROM
APTIFY.dbo.vwTopicCodeLinks vwTopicCodeLinks
WHERE
vwTopicCodeLinks.TopicCodeID = 16
)
AND
APTIFY..vwPersons.ID IN (
SELECT
RecordID
FROM
APTIFY.dbo.vwTopicCodeLinks vwTopicCodeLinks
WHERE
vwTopicCodeLinks.Value = N'Yes, Please'
) )
)
vwMeetingsRegistrants from the b query are producing the same records as orderkgdetailsextended from query. I cannot see ANY difference in those queries - which perhaps shows my lack of understanding the query behaviour.
BIG Thanks for any points guys! :)
As it came out, incorrectly structured query is a result of badly configured application, Aptify.