SQL query - select max where a count greater than value - mysql

I've got two tables with the following structure:
Question table
id int,
question text,
answer text,
level int
Progress table
qid int,
attempts int,
completed boolean (qid means question id)
Now my questions is how to construct a query that selects the max level where the count of correct questions is greater than let's say 30.
I created this query, but it doesn't work and I don't know why.
SELECT MAX(Questions.level)
FROM Questions, Progress
WHERE Questions.id = Progress.qid AND Progress.completed = 1
GROUP BY Questions.id, Questions.level
Having COUNT(*) >= 30
I would like to have it in one query as I suspect this is possible and probably the most 'optimized' way to query for it. Thanks for the help!

This sort of construct will work. You can figure out the details.
select max(something) maxvalue
from SomeTables
join (select id, count(*) records
from ATable
group by id) temp on ATable.id = temp.id
where records >= 30

Do it step by step rather than joining the two tables. In an inner select find the questions (i.e. the question ids) that were answered 30 times correctly. In an outer select find the corresponding levels and get the maximum value:
select max(level)
from questions
where id in
(
select qid
from progress
where completed = 1
group by qid
having count(*) >= 30
);

Related

When will recursive query stop in this case?

Given this table description.
I have written a query to find Users who logged in for 5 or more consecutive days.
WITH RECURSIVE
rec_t AS
(SELECT id, login_date, 1 AS days FROM Logins
UNION ALL
SELECT l.id, l.login_date, rec_t.days+1 FROM rec_t
INNER JOIN Logins l
ON rec_t.id = l.id AND DATE_ADD(rec_t.login_date, INTERVAL 1 DAY) = l.login_date
)
SELECT * FROM Accounts
WHERE id IN
(SELECT DISTINCT id FROM rec_t WHERE days = 5)
ORDER BY id
Code Explanation :
For every id and login date, match the CTE table with the same id and +1 login_date.
the "days" column just increments +1 everytime the same user_id appears.
The Problem:
Although the query works fine, I just don't know where am I asking the query to stop the recursion. There isn't a "where" in RECURSIVE CTE definition. However, the inner join might help to dictate that there are no more login_date to match on. But I am uncertain that is the case.

Can't address parent field in query with multiple subqueries

EDIT: Better explanation
I have a page with a job. The job as an idea and three skills (skill_ids) and skill requirements (a user must have at least this skill value to be qualified).
I click on the job to find candidates, so I have the job_id and the three skill_ids and skill_id_requirements. So I can do this so far as the first answer proposed with joins. I find all users who have the three skills. The skills are saved in skill_ratings. So far it works as I use to find the skill_id's only.
But now I want the value and here I have my code where I compute the final value (called rating). The rating respects all given values, but isn't a simple average or the sum of all. That's why I need the long horrible code. In the long horrible code I usually insert a user's ID. But here I need all user_id's who have the skills mentioned above just to calculate if they are qualified. This is dynamic.
I'm having a table where I want to find people who are qualified for a position under some requirements. Here I work with one table called skill_ratings, but (as far as I see) need to add some subqueries. And here I have the problem. There are many subqueries and I've tried to address a parent query field. But it only seems to work in a first-grade subquery to a parent query.
Here's my structure:
SELECT * FROM table t
WHERE EXISTS (SELECT * FROM table d WHERE x > 1
AND b=t.id
AND y <= (SELECT a FROM (MAIN SUBQUERY WITH CALCULATIONS)))
GROUP BY xyx
But the error I get is: #1054 - Unknown column 'skra.usr_id_get' in 'where clause'. skra is the parent table in this case.
I want to get the following (pseudo-sql):
SELECT all FROM table t AS x
WHERE EXISTS (
SELECT all FROM table t AS y
WHERE y.skill_id = 1
AND y.usr_id_get = t.usr_id_get
AND y.value <= (my algorithm)
)
The main subquery is important so far as I want to get a computed number. Elsewhere the code works because I were able to work with predefined PHP-variables for a user's ID. But I can't do this here as I need to find the users within the boundaries of the where-clauses.
How can I solve this? Because addressing a parent-field in a subquery seems to be limited to a first-grade subquery.
EDIT: Code
Code removed due to project status.
Error: #1054 - Unknown column 'c.usr_id_get' in 'where clause'
We want users that have certain skills of certain levels. For example all users that have skill 1 with at least level 20 and skill 2 with at least level 70.
Here is an algorithm:
First of all we must get the skill levels. A user has several skill ratings and the average rating per skill is the level.
Then we want a table of criteria (skill 1 / level 20, skill 2 / level 70 in our example).
We collect all user skill levels that match the criteria (EXISTS clause) and then
keep the users that match all skill levels (count(*) = <desired number of skills>).
The query:
select
sr.usr_id_get
from
(
select usr_id_get, skill_id, avg(value) as level
from skill_ratings
group by usr_id_get, skill_id
) sr
where exists
(
select *
from
(
select 1 as skill_id, 20 as level
union all
select 2 as skill_id, 70 as level
) criteria
where sr.skill_id = criteria.skill_id
and sr.level >= criteria.level
)
group by usr_id_get
having count(*) = 2;
You can also make criteria a real (temporary) table. Then your query stays the same, no matter how many skills are requested. You'd have
where exists
(
select *
from criteria
where sr.skill_id = criteria.skill_id
and sr.level >= criteria.level
)
group by usr_id_get
having count(*) = (select count(*) from criteria);
then.
This looks like it could be done with a simple JOIN:
SELECT T.*
FROM your_table T
JOIN other_table Y ON (
T.usr_id_get = Y.usr_id_get
AND T.skill_id = 1
AND Y.value <= [...]
)
If you need to perform some sort of calculations before the join, then you could join with a subquery:
SELECT T.*
FROM your_table T
JOIN (
SELECT *
FROM other_table Y
WHERE Y.skill_id = 1
AND Y.value = [...]
) Y USING(usr_id_get)
If I understand correctly, you have a user, say user 123, and a skill, say skill 99. Now you want to get the avarage rating for user 123 and skill 99 and then find all users with an equal or better average rating on that skill.
This is how to get the avarage ratings for skill 99 per user:
select usr_id_get, avg(value)
from skill_ratings
where skill_id = 99
group by usr_id_get;
This is how to get all users with an equal or better avarage rating for skill 99 than user 123:
select usr_id_get
from skill_ratings
where skill_id = 99
group by usr_id_get
having avg(value) >=
(select avg(value) from skill_ratings where skill_id = 99 and usr_id_get = 123);
Add to this whatever other criteria you need.

mysql count result status correct and group by user id

I made a query in which there are result being compared from a pre defined answers table to the answers which a user enters for multiple questions . The problem is now i want to get the total score (which i can calculate according to status correct ) of each user . The following query gives me all the users data with status of each question's answer to be correct or not .
SELECT qa.question_id, qa.test_id, uta.user_answer,uta.user_id, qa.type,
qa.answers correct_answer,
CASE WHEN uta.user_answer = qa.answers THEN 'correct' ELSE 'incorrect' END
AS status
FROM questions_answer qa
LEFT JOIN
(
SELECT user_id, type, test_id, question_id,
GROUP_CONCAT(answers ORDER BY answers) AS user_answer,
timestamp from user_test_answers
WHERE test_id = '1'
GROUP BY user_id, question_id
) uta
ON qa.question_id = uta.question_id
where qa.test_id=1
If i add GROUP BY user_id in the end it also groups the result by user_id But how to count all the status correct so that i can get the total number of correct answers count .
First of all, you're misusing, and proposing to misuse, GROUP BY. When you use it correctly, every column in your result set is either also mentioned in the GROUP BY clause or is an aggregate column. Please read up on GROUP BY and use it correctly or you'll have a hard time troubleshooting your queries.
Secondly, you can wrap your query up in an outer aggregate query and do the summary. This kind of thing should work, as long as the query in your question works.
SELECT user_id, test_id,
100 * SUM(status='correct') / COUNT(status) AS percent_correct,
100 * SUM(status='incorrect') / COUNT(status) AS percent_incorrect
FROM (
/* your entire query from your question */
) AS results
GROUP BY user_id, test_id
ORDER BY user_id, test_id

Combine search from 2 rows in mysql

I run a survey where all answers are stored in a separate row in the 'survey' table.
My table looks like this:
(ID,user_id,Q,A)
(1,10,'laundry','oxiclean')
(2,10,'laundry','tide')
(3,10,'laundry','pods')
(4,11,'laundry','spray n wash')
(5,11,'laundry','resolve')
(6,12,'laundry','oxiclean')
(7,13,'laundry','oxiclean')
I now need to pull the count of user id that selected ONLY specific products.
"SELECT *, count(user_id) FROM survey WHERE Q='laundry' GROUP BY a"
the above will give a an overall COUNT but I need to get my count based on users that selected ONLY 'oxiclean' for example. This should return 2.
Or users that selected 'oxiclean' AND 'tide' ONLY.
How do I go about performing this 'combination' of results pulled from different rows?
Thanks a lot!
select user_id from survey group by user_id having count(user_id) = 1
This retrieves a list of users which have only one answer in the survey. Use it as a filter condition:
select q,a,count(user_id)
from survey
where a = 'oxiclean'
and user_id in (select user_id from survey group by user_id having count(user_id) = 1)
You can achieve that using a subquery, for your case it will be something like that :
SELECT *, COUNT(user_id)
FROM survey AS s
WHERE Q = 'laundry'
AND A = 'oxiclean'
AND user_id NOT IN (SELECT user_id FROM survey WHERE Q = s.Q AND A != s.A);
s.Q and s.A refer to the parent field so you don't have to reinject the name a second time.
Downside : the query works only if you want one specific answer.
If you want one query to retrieve the overall count, this one should do the trick :
SELECT A, COUNT(user_id)
FROM (
SELECT A, user_id
FROM survey
WHERE Q='laundry'
GROUP BY user_id
HAVING COUNT(user_id) = 1
) AS t
GROUP BY A
Downside : the query give only answers who have only at least one unique user_id as seen here, and this syntax create a temporary table which is something to avoid for performance reasons.

SQL Query to count IDs with exactly 91 duplicates

I've got a mySQL database of survey responses. Each one has a userID, a questionID and the actual answer. Now I'm trying to write a report that will tell me how many people actually completed the survey as opposed to stopped halfway through. So I'm trying to figure out how to write a query that will count all of the userIDs that are duplicated exactly 91 times.
Be gentle, this is my first stackoverflow question.
You have to group by having count(*) = 91
select userId from myTable group by userId having count(*) = 91
http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html
I don't have data to test this, but this may help:
SELECT COUNT(*) AS userCount, userId
FROM tbl
GROUP BY userId
HAVING userCount = 91
If the questions are ordered, then you could check for the last question ID:
SELECT COUNT(*) FROM SurveyResponses WHERE QuestionId= [last_question_id]