Order by first results that do not go over - mysql

How can you order by two fields based on the value not being greater than another? Here is an example of what I have written.
SELECT *
FROM contest_results r
LEFT
JOIN participant_users u
ON r.participant_id = u.id
LEFT
JOIN contest_entry_tie_answers t
ON u.id = t.participant_id
LEFT
JOIN contest_answers a
ON a.question_id = t.tie_breaker_question_id
WHERE r.contest_id = 20
ORDER BY r.correct_answers DESC,
t.answer <= a.possible_answer ASC
Now imagine that this query returns two rows and contest_entry_tie_answers.answer has a value of 103 and another of 106. Finally, imagine that contest_answers.possible_answer has a value of 105 because that field was checked as the correct answer. I want to be able to order the results as contest_entry_tie_answers.answer <= contest_answers.possible_answer.
That would mean the 103 answer would be shown first in the event that the previous order by contest_results.correct_answers returns a tie value for both. Then the 106 result would show last because it went over the actual correct answer of 105.
Is there a way to do this? I hope this made some sense.

I believe I found the solution by doing the following:
SELECT *
FROM contest_results r
LEFT
JOIN participant_users u
ON r.participant_id = u.id
LEFT
JOIN contest_entry_tie_answers t
ON u.id = t.participant_id
LEFT
JOIN contest_answers a
ON a.question_id = t.tie_breaker_question_id
WHERE r.contest_id = 20
ORDER BY r.correct_answers DESC,
case
when t.answer <= a.possible_answer then 0
when t.answer > a.possible_answer then 1
end,
t.answer
DESC
This seems to work well from my initial testing.

Related

Order by inside the LEFT JOIN

I am trying to write a query. I got it work half way, but I am having problems with the LEFT JOIN.
I have three tables:
user
user_preferences
user_subscription_plan
User will always have one user_preference, but it can have many or no entries in the user_subscription_plan
If the user has no entry in the user_subscription_plan, or if he has only one then my sql works. If I have more then one, then I have issue. In the case of two entries, how can I make it to return the last one entered? I tried playing with ORDER statement, but it does not work as expected. Somehow I get empty rows.
Here is my query:
SELECT u.id AS GYM_USER_ID, subscription_plan.id AS subscriptionId, up.onboarding_completed AS CompletedOnboarding,
(CASE
WHEN ((up.onboarding_completed = 1)
AND (ISNULL(subscription_plan.id)))
THEN 'freemiun'
WHEN (ISNULL(up.onboarding_completed)
AND (ISNULL(subscription_plan.id)))
THEN 'not_paying'
END) AS subscription_status
FROM user AS u
INNER JOIN user_preferences up ON up.user_id = u.id
LEFT JOIN (
SELECT * FROM user_subscription_plan AS usp ORDER BY usp.id DESC LIMIT 1
) AS subscription_plan ON subscription_plan.user_id = u.id
GROUP BY u.id;
If I run it as it is, then subscription_plan.id AS subscriptionId is always empty.
If I remove the LIMIT clause, then its not empty, but I am still getting the first entry, which is wrong in my case
I have more CASE's to cover, but I can't process until I solve this problem.
Please try to use "max(usp.id)" that "group by subscription_plan.user_id" instead of limit 1.
If you limit 1 in the subquery, the subquery's result will always return only 1 record (if the table has data).
So the above query can be rewritten like this.
Sorry, I didn't test, because I don't have data, but please try, hope this can help.
SELECT
u.id AS GYM_USER_ID,
subscription_plan.id AS subscriptionId,
up.onboarding_completed AS CompletedOnboarding,
(CASE
WHEN
((up.onboarding_completed = 1)
AND (ISNULL(subscription_plan.id)))
THEN
'freemiun'
WHEN
(ISNULL(up.onboarding_completed)
AND (ISNULL(subscription_plan.id)))
THEN
'not_paying'
END) AS subscription_status
FROM
user AS u
INNER JOIN
user_preferences up ON up.user_id = u.id
LEFT JOIN
(SELECT
usp.user_id, MAX(usp.id)AS id
FROM
user_subscription_plan AS usp
GROUP BY usp.user_id) AS subscription_plan ON subscription_plan.user_id = u.id;

SQL query that combines 2 into 1, specifically it counts the number of people in each group for each group

I've found a few posts in here that are similar, but doesn't work with what i'd like to do...
similar post: Trying to write a query that counts multiple things with different where cases
similar post: Query that Counts records with a WHERE clause
what I want to do is I have some... 200 groups, and within those groups are people with specific application dates. I want a count of how many people are in those groups that have a application date that falls within a specific range.
So this is the first method i've been using, but it only works for 1 group at a time
SELECT count(*) as count
FROM membersapplication ma
INNER JOIN members mb on mb.mbr_id = ma.mbr_id
WHERE (GPL_ID = 20179) and (ma.mpl_effectivedate >= '2/01/2015' and ma.mpl_effectivedate <= '4/30/2015') and (ma.mpl_cancellationdate is null)
This code takes the count of anyone that falls under GPL_ID 20179 (group placement id), i have 200 GPL_ID's that I would like this to run for, there is never a duplicate GPL_ID.
SELECT Gr.GPL_ID, Gr.GPL_Effectivedate, G.GRP_Enrolltype, G.GRP_Name, G.GRP_ID, G.GRP_Executive
FROM groupsreview gr
INNER JOIN groups g on gr.grp_ID = g.grp_ID
WHERE (GRP_ENROLLTYPE = 1) and (gp.gpl_effectivedate >= '4/30/2014' and gp.gpl_effectivedate <= '4/30/2015')
order by grp_name asc
This code gives me a list of every GPL_ID that I want (based off GRP_Enrolltype = 1) that falls within my desired date range
I basically would like to combine the two codes so that the 2nd set of code adds another column that has a count based off the fist code
Seems you really just need add GROUP BY to your query:
SELECT ma.GPL_ID, count(*) as count
FROM membersapplication ma
INNER JOIN members mb
ON mb.mbr_id = ma.mbr_id
where (ma.mpl_effectivedate >= '2/01/2015' and ma.mpl_effectivedate <= '4/30/2015')
AND (ma.mpl_cancellationdate is null)
GROUP BY ma.GPL_ID
This should do it. But I would double check the dates, I just used the ones you supplied; they don't match, and I am not sure if they should:
SELECT ma.GPL_ID, count(*) as count
FROM groups g
INNER JOIN groupsreview AS gr ON g.grp_ID = gr.grp_ID
INNER JOIN membersapplication AS ma ON gr.GPL_ID = ma.GPL_ID
INNER JOIN members AS mb ON mb.mbr_id = ma.mbr_id
WHERE g.GRP_ENROLLTYPE = 1
AND gr.gpl_effectivedate BETWEEN 20140430 AND 20150430
AND ma.mpl_effectivedate BETWEEN 20150201 and 20150430
AND ma.mpl_cancellationdate IS NULL
GROUP BY ma.GPL_ID
;
Judging from your question's wording, it feels a little odd to group by GPL_ID instead of grp_ID.
Not sure if this will work, but I can give it a try:
SELECT
*
FROM
(SELECT
count(*) as count, GPL_ID
FROM
membersapplication ma
inner join members mb ON mb.mbr_id = ma.mbr_id
where
(ma.mpl_effectivedate >= '2/01/2015'
and ma.mpl_effectivedate <= '4/30/2015')
and (ma.mpl_cancellationdate is null)
GROUP BY GPL_ID) T1
INNER JOIN
(SELECT
Gr.GPL_ID,
Gr.GPL_Effectivedate,
G.GRP_Enrolltype,
G.GRP_Name,
G.GRP_ID,
G.GRP_Executive
FROM
groupsreview gr
inner join groups g ON gr.grp_ID = g.grp_ID
WHERE
(GRP_ENROLLTYPE = 1)
and (gp.gpl_effectivedate >= '4/30/2014'
and gp.gpl_effectivedate <= '4/30/2015')) T2
ON T1.GPL_ID = T2.GPL_ID
Basically you should approach this by combining joins and then grouping on GPL_ID along with a having clause. Here's what came up with.
SELECT Gr.GPL_ID, Gr.GPL_Effectivedate, G.GRP_Enrolltype, G.GRP_Name, G.GRP_ID, G.GRP_Executive
count(*) as grp_count
FROM membersapplication ma
INNER JOIN members mb on mb.mbr_id = ma.mbr_id
INNER JOIN groupsreview gr on mb.GPL_ID = gr.GPL_ID
INNER JOIN groups g on gr.grp_ID = g.grp_ID
WHERE (GRP_ENROLLTYPE = 1) and (gp.gpl_effectivedate >= '4/30/2014' and gp.gpl_effectivedate <= '4/30/2015')
GROUP BY Gr.GPL_ID, Gr.GPL_Effectivedate, G.GRP_Enrolltype, G.GRP_Name, G.GRP_ID, G.GRP_Executive
HAVING (ma.mpl_effectivedate >= '2/01/2015' and ma.mpl_effectivedate <= '4/30/2015') and (ma.mpl_cancellationdate is null)
order by grp_name asc
Hopefully this helps

MySQL group by twice and COUNT

Some sql query gives me the following result:
As you can see, it already has GROUP BY.
So what I need? I need to group it again (by treatment_name) and count rows for each group. See more details on screenshot.
Here is full query:
SELECT
treatment_summaries.*
FROM `treatment_summaries`
INNER JOIN
`treatments`
ON
`treatments`.`treatment_summary_id` = `treatment_summaries`.`id`
AND
(treatment <> '' and treatment is not null)
INNER JOIN
`treatment_reviews`
ON
`treatment_reviews`.`treatment_id` = `treatments`.`id`
INNER JOIN
`conditions_treatment_reviews`
ON
`conditions_treatment_reviews`.`treatment_review_id` = `treatment_reviews`.`id`
INNER JOIN
`conditions` ON `conditions`.`id` = `conditions_treatment_reviews`.`condition_id`
INNER JOIN `conditions_treatment_summaries` `conditions_treatment_summaries_join`
ON
`conditions_treatment_summaries_join`.`treatment_summary_id` = `treatment_summaries`.`id`
INNER JOIN `conditions` `conditions_treatment_summaries`
ON `conditions_treatment_summaries`.`id` = `conditions_treatment_summaries_join`.`condition_id`
WHERE
`conditions`.`id` = 9
AND `conditions`.`id` IN (9)
AND (latest_review_id is not null)
GROUP BY
treatment_reviews.id
ORDER BY
treatment_summaries.reviews_count desc
LIMIT 20 OFFSET 0
Maybe there is another issue, cause GROUP BY should not leave same lines (for given column), but anyway you can wrap it like this:
SELECT * FROM ( YOUR_SQL_SELECT_WITH_EVERYTHING ) GROUP BY id
So the result you get will behave as another table and you can do all operations like GROUP BY again.

condition LEFT JOIN with DISTINCT

select wyraz_id, count(wyraz_id) as c from worek w
group by wyraz_id order by c desc limit 11
This query gives me back top 11 favourited wyraz_id from table worek.
LEFT JOIN wyraz FROM wyrazy wy WHERE wy.wyraz_id = w.wyraz_id
The problem is, that wyraz_id in this case should apply to DISTINCT results only.
select wyraz_id, count(wyraz_id) as c from worek w
LEFT JOIN wyraz FROM wyrazy wy
WHERE wy.wyraz_id = w.wyraz_id Having distint(wyraz_id)???
group by wyraz_id order by c desc limit 11
I've managed to go around it by doing another query on the go, but seems pointless really if you can do all that with a simple join.
$d = $row['wyraz_id'];
"select wyraz from wyrazy where wyraz_id='{$d}'";
Thank you kindly for any suggestions.

MySQL Subquery returned more than 1 row

I cannot figure out why this is not working. Basically, I am running a subquery to count all rows of p.songid WHERE trackDeleted=0. The subquery works fine when I execute it by itself, but when I implement I get "subquery returned more than 1 row".
SELECT u.username, u.id, u.score, s.genre, s.songid, s.songTitle, s.timeSubmitted, s.userid, s.insWanted, s.bounty,
(SELECT COUNT(p.songid)
FROM songs s
LEFT JOIN users u
ON u.id = s.userid
LEFT JOIN posttracks p
ON s.songid = p.songid
WHERE p.trackDeleted=0
GROUP BY s.timeSubmitted ASC
LIMIT 25)
AS trackCount
FROM songs s
LEFT JOIN users u
ON u.id = s.userid
LEFT JOIN posttracks p
ON s.songid = p.songid
WHERE paid=1 AND s.timeSubmitted >= ( CURDATE() - INTERVAL 60 DAY )
GROUP BY s.timeSubmitted ASC
LIMIT 25
Obviously, a sub-query can't return more than one row, as this makes no sense. You only expect one value to be returned - COUNT(p.songid) - yet you GROUP BY s.timeSubmitted, which will make it return multiple rows, and multiple counts of p.songid.
Think about it this way, a subquery in the SELECT statement like you have needs to return a single value since it is going to act like just another column in your select list. Since you have a LIMIT 25 on yours, you're obviously expecting more than one value back, which is inocrrect for this usage.
OK, your query is a mess. Not only is the subquery broken, but I'm pretty sure the GROUP BY s.timeSubmitted ASC isn't doing what you think think it does. (Did you mean ORDER BY instead?) It might help if you explained in words what you're trying to accomplish.
Anyway, I'm going to take a wild guess and suggest that this might be what you want:
SELECT
u.username, u.id, u.score, s.genre, s.songid, s.songTitle,
s.timeSubmitted, s.userid, s.insWanted, s.bounty,
COUNT(p.songid) AS trackCount
FROM songs s
LEFT JOIN users u ON u.id = s.userid
LEFT JOIN posttracks p ON p.songid = s.songid AND p.trackDeleted = 0
WHERE paid = 1 AND s.timeSubmitted >= ( CURDATE() - INTERVAL 60 DAY )
GROUP BY s.songid
ORDER BY s.timeSubmitted ASC
LIMIT 25
Edit: Fixed the COUNT() so that it will correctly return 0 if there are no matching tracks.