How Do I Count Number of Males and Females - mysql

I have the query as follows:
select d.question, b.response, count(b.response)
from sl_flow a
INNER JOIN ul_attempt_responses b on a.question_id = b.question_id and b.type = 1
INNER JOIN us_attempts c on c.id = b.attempt_id
INNER JOIN ss_questions d on d.id = a.question_id
where a.status = 1
and a.ckm_question = 0
and b.response
group by a.question_id, b.response
order by a.question_order asc
The above gives me the questions that I have in the DB which are active and their responses and counts.
However I need a query that will give me number of males and females that answered each of the question. Therefore, I have another query that gives me the number of males and females which is:
SELECT
concat(a.response, 's') as gender,
count(a.response) as count
FROM
ul_attempt_responses a
INNER JOIN us_attempts b ON a.attempt_id = b.id
WHERE
a.question_id = 6 and a.type = 0 AND trim(a.response) != ''
GROUP by a.response;
I am not sure, how to do so. For the gender, the question_id is 6 and type on the a table has to be 0 (the a table is ul_attempt_responses).
This is what I got so far. However, it appears that the results I am getting may not be consistent:
SELECT
gender.question
,coalesce(sum(case final.Response when 'male' then gender.total end),0) as 'Males'
,coalesce(sum(case final.Response when 'female' then gender.total end),0) as 'Females'
FROM
(SELECT
stats . *,
(CASE concat(stats.userid, stats.QuestionID, stats.type)
WHEN #curType THEN #curRow:=coalesce(#curRow, 0) + 1
ELSE #curROw:=1
AND #curType:=concat(stats.userid, stats.QuestionID, stats.type)
END) + 1 AS rank
FROM
(SELECT
d.question as Question,
a.user_id AS UserID,
c.question_id AS QuestionID,
c.type as Type,
c.response AS Response,
a.campaign_id as campaign_id
FROM
us_attempts a
INNER JOIN ul_attempt_responses c ON a.id = c.attempt_id
RIGHT OUTER JOIN ss_profile_questions d ON c.question_id = d.id AND c.type = 0
LEFT OUTER JOIN sl_profile_flow f ON c.question_id = f.profile_question_id
RIGHT OUTER JOIN us_users g ON g.id = a.user_id
WHERE
f.status = 1
ORDER BY a.user_id , c.question_id , c.type , a.id desc) stats) final
INNER JOIN
(select b.user_id, c.question as question, count(1) as total
from ul_attempt_responses a
INNER JOIN us_attempts b on a.attempt_id = b.id
INNER JOIN ss_questions c on a.question_id = c.id and a.type = 1
group by b.user_id, c.id) gender on final.UserID = gender.user_id
where
final.rank = 2 and final.QuestionID = 6 and final.campaign_id = 3
group by gender.question;
Is there a way I can reduce the above query, or is there a better optimized way?

You could use a combination of sum and case/if to get the counts. Given your full table structures are not clear, I am assuming you have a table (or an SQL that can produce a set of rows) with the following fields:
response_id
question_id
response
Then an SQL such as
select question_id
, response
, sum(if(gender='M',1,0)) as males
, sum(if(gender='F',1,0)) as females
from (select q.question_id
, q.response
, g.response as gender from answers as q
left join answers as g on q.response_id=g.response_id and g.question_id=6
where q.question_id!=6) as t
group by question_id, response
would give you a result of the form
question_id,response,males,females
1,A,1,2
1,B,1,0
2,A,0,1
2,B,1,1
2,C,1,0
To explain the code, the sub query produces a set of rows for each response with the question mapped with the gender question's response. In the main select statement the if statement produces a 1 for the specific gender in the proper column and summing them up gives you how many of that specific gender responded to that question.
EDIT
As suggested by #Strawberry, the shorter version would be
select q.question_id
, q.response_id
, sum(g.response='M') as males
, sum(g.response='F') as females
from answers as q
left
join test as g
on q.response_id = g.response_id
and g.question_id = 6
where q.question_id != 6
group
by q.question_id
, q.response

Related

can't write the correct syntax for the next query

There are 3 entities besides User : Answer, Question and Votes_on_Answers which contains users votes of answers
Answer is associated with Question table by Many-To-One relationship
I need to write query that sums the amount of votes of answer and sort them but I have diffulty with writing the if statement
select a.id, a.question_id, a.user_id,
case
when sum(voa.vote) = null
then 0
else sum(voa.vote)
end as i
from answer as a left join votes_on_answers as voa on a.id = voa.answer_id
where a.question_id = 1
group by a.id order by i desc;
This query returns:
id question_id i
1 1 3
2 1 -2
3 1 null
In this case you could avoid the case .. when and use ifnul()
select a.id
, a.question_id
, sum(ifnull(voa.vote,0)) as i
from answer as a
left join votes_on_answers as voa on a.id = voa.answer_id
where a.question_id = 1
group by a.id
order by i desc;
or using case
select a.id
, a.question_id
, sum(case when voa.vote is null then 0 else voa.vote end)) as i
from answer as a
left join votes_on_answers as voa on a.id = voa.answer_id
where a.question_id = 1
group by a.id
order by i desc;
You might find that a correlated subquery is simpler and faster . . . and you don't have to worry about null values:
select a.id, a.question_id, a.user_id,
(select coalesce(sum(v.votes), 0)
from votes_on_answers voa
where a.id = voa.answer_id
) as i
from answer a
where a.question_id = 1
order by i desc;
For performance you want an index on votes_on_answers(answer_id).
Avoiding the outer group by is a win from the performance perspective. When there are no matches in voa, the count(*) returns 0.

count a specific row on a nested query

I'm trying to count the number of records on a particular field with the query below.
SELECT COUNT(DISTINCT CASE WHEN seen='n' and reciever_id=1 THEN 'varb' ELSE 'novarb' END) AS count ,c.id, c.vmsg, c.sender_id, p.fname, p.lname, p.profile_pix, p.profile_id
FROM chats c LEFT JOIN profile p ON c.sender_id = p.profile_id
WHERE c.reciever_id = 1 AND c.id in (SELECT MAX(c.id) as id FROM chats c
GROUP BY c.sender_id )
But the answer i get only returns it just one record whiles there other hundreds to be displayed
If you use varb and novarb the dictinct count is max 2 if you have 1 mean that you have one condition only
could be you need that count the number of varb entries
SELECT COUNT(
CASE WHEN seen ='n' and reciever_id=1
THEN 'varb'
ELSE NULL
END) AS count ,c.id, c.vmsg, c.sender_id, p.fname, p.lname, p.profile_pix, p.profile_id
FROM chats c
LEFT JOIN profile p ON c.sender_id = p.profile_id
WHERE c.reciever_id = 1 AND c.id in (
SELECT MAX(c.id) as id FROM chats c
GROUP BY c.sender_id )
I usually use SUM() for this purpose. If I understand correctly, you want the number of rows that meet the condition and don't meet the condition:
SELECT SUM( seen = 'n' and reciever_id = 1 ) as varb,
SUM( not (seen = 'n' and reciever_id = 1) ) as novarb,
c.id, c.vmsg, c.sender_id, p.fname, p.lname, p.profile_pix, p.profile_id
FROM chats c JOIN -- I doubt a left join is necessary
profile p
ON c.sender_id = p.profile_id
WHERE c.reciever_id = 1 AND
c.id in (SELECT MAX(c2.id) FROM chats c2 GROUP BY c2.sender_id)

mysql subquery select with field from query

i have a little problem with a subquery in sql.
her the query
SELECT st.title, count(q.id) as question_count, max(a.id) as maxid,
sum(case when a.answer is not null then 1 else 0 end) as answer_count, g.user_id as game_user_id,
a.game_id as a_game_id, a.modified as finished, (select modified as finished from answers a where a.id = g.maxid limit 1) as subquery
FROM games g
left join answers a on(a.game_id = g.id)
left join questions q on(a.question_id = q.id)
left join sessions s on(s.id = q.session_id)
left join sessiontypes st on(st.id = s.sessiontype_id)
WHERE g.user_id = 21
group by g.id
having(question_count = answer_count)
order by finished DESC;
i want that the subquery returns the modified value from answers where the id is the highest grouped by game.
so i tried to select max(id) as maxid... and the use max id in the subquery. where a.id = maxid. nice try, but dont work.
mysql error is this one: Reference 'maxid' not supported (reference to group function)
can anybody give a hint how to solve that?
Join on a subquery which returns the MAX(answers.id) grouped by the answers.game_id.
Then use that maxid to join on the answers table to get the row of the corresponding answers.id.
Not sure, how your result is supposed to look, in your select I removed a.modified AS finished, and replaced it with the modified column of the row with maxid.
SELECT
st.title,
count(q.id) AS question_count,
sum(
CASE
WHEN a.answer IS NOT NULL THEN
1
ELSE
0
END
) AS answer_count,
g.user_id AS game_user_id,
a.maxid,
a.game_id AS a_game_id,
modifiedAnswer.modified AS finished,
FROM
games g
LEFT JOIN (SELECT MAX(answers.id) AS maxid, game_id FROM answers GROUP BY answers.game_id) AS a ON (a.game_id = g.id)
LEFT JOIN answers AS modifiedAnswer ON modifiedAnswer.id = a.maxid
LEFT JOIN questions q ON (a.question_id = q.id)
LEFT JOIN sessions s ON (s.id = q.session_id)
LEFT JOIN sessiontypes st ON (st.id = s.sessiontype_id)
WHERE
g.user_id = 21
GROUP BY
g.id
HAVING
(
question_count = answer_count
)
ORDER BY
finished DESC;

Mysql select count on left join with condition not working

I need to count number of records on left table, i read other questions and end up with this query but the condition on COUNT is ignored
SELECT a.name, COUNT( f.status <> 'e' ) AS total
FROM album AS a LEFT JOIN photo AS f
ON a.id = f.idalbum
WHERE a.iduser = 4
GROUP BY a.id
is MySQL 5 DB
you cant specify a condition inside COUNT statment.
try this
SELECT a.name, COUNT( f.status ) AS total
FROM album AS a LEFT JOIN photo AS f
ON a.id = f.idalbum
WHERE a.iduser = 4 or f.status <> 'e'
GROUP BY a.id
What if you do:
SELECT a.name, COUNT( f.status ) AS total
FROM album AS a LEFT JOIN photo AS f
ON a.id = f.idalbum
WHERE a.iduser = 4 and f.status != 'e'
GROUP BY a.id

Multiple Left Joins in MySQL

I seem to be having some issues getting my multi left join to give me the correct results, it gives me the id just fine however i cannot seem to get the link to give me the resulting question instead of the ID.
Code below.
SELECT
a.id as id,
a.clientid as clientid,
a.comp_id as compid,
a.title as title,
a.firstname as firstname,
a.lastname as lastname,
a.countrycode as countrycode,
a.mobile as mobile,
a.question1_answer as question1_answer,
a.question2_answer as question2_answer,
a.question3_answer as question3_answer,
a.timestamp as timestamp,
b.comp_name as comp_name,
b.comp_id as comp_id,
a.question1 as question1,
a.question2 as question2,
a.question3 as question3
FROM
competition_entries AS a
LEFT JOIN
competition as b
ON
a.comp_id = b.id
LEFT JOIN
questions as q
ON
a.question1 = q.question_id
AND
a.question2 = q.question_id
AND
a.question3 = q.question_id
WHERE
a.comp_id = '$download_id'
However each time i call question1 / question2 / question3 - the only results shown are the number values that are corresponding to their ID within the other table.
You need to join to the question table three times, once for each id you have:
SELECT a.id as id, a.clientid as clientid, a.comp_id as compid, a.title as title,
a.firstname as firstname, a.lastname as lastname, a.countrycode as countrycode,
a.mobile as mobile,
a.question1_answer as question1_answer,
a.question2_answer as question2_answer,
a.question3_answer as question3_answer,
a.timestamp as timestamp,
b.comp_name as comp_name,
b.comp_id as comp_id,
a.question1 as question1id,
a.question2 as question2id,
a.question3 as question3id,
q1.question as question1,
q2.question as question2,
q3.question as question3
FROM competition_entries a LEFT JOIN
competition as b
ON a.comp_id = b.id LEFT JOIN
questions as q1
ON a.question1 = q1.question_id left join
questions q2
on a.question2 = q2.question_id left join
questions q3
on a.question3 = q3.question_id
WHERE a.comp_id = '$download_id'