Show count 0 when condition is not met in MySQL group by - mysql

Sample Records:
examid setcode answer
------- -------- --------
10 A A
10 A B
10 A X
10 B A
10 B B
10 B C
I am trying to find count group by setcode where answer is X.
I have tried the following query:
SELECT setCode,COUNT(answer) FROM mcq_answer WHERE examid=10 AND answer='X' GROUP BY setCode
This one is returning the following result:
setcode count
------- --------
A 1
But I am looking for the following:
setcode count
------- --------
A 1
B 0
Setcode is dynamic here. I have mentioned A and B only. There may be more setocdes as C,D,E,F etc. How can I do it. I am using MySQL

you can use below query
SELECT C.setCode ,
SUM(CASE WHEN B.setcode IS NULL THEN 0
ELSE 1
END) AS answer
FROM ( SELECT A.setCode ,
COUNT(1) AS cnt
FROM mcq_answer A
GROUP BY A.setCode
) C
LEFT JOIN mcq_answer b ON C.setcode = B.setcode
AND B.answer = 'X'
GROUP BY C.setCode

You can use SUM + IF to have this result:
SELECT `setCode`, SUM(if (`answer`='X', 1,0)) as answer
FROM `mcq_answer`
WHERE examid=10
GROUP BY `setcode`

Try:
SELECT A.setcode,
COUNT(CASE WHEN B.answer ='X' THEN B.answer ELSE NULL END) as count_x
FROM
(SELECT DISTINCT setcode FROM YOUR_TABLE) A
LEFT JOIN
YOUR_TABLE B
ON A.setcode = B.setcode
GROUP BY A.setcode;
It also works for dynamic set of values for setcode.

Related

How to check then display the result of two tables and check is exist or not-exist?

Tabel_A
---------
id name
1 Kursi
2 Roda
3 Gigi
Tabel_B
---------
id id_tabel_A
1 2
Result
--------
name Status
Kursi 0
Roda 1
Gigi 0
Query of the Result : …………………… ?
use left join and case when
select name, case when b.id_tabel_A is null then 0 else 1 end as status
from tableA a left join tableB b on a.id=b.id_tabel_A
You apply IF syntax
SELECT a.name,
IF(
(
SELECT count(b.id_tabel_A)
from Tabel_B as b
WHERE b.id_tabel_A = a.id -- connect
) > 0
, "YES", "NO") as status
from Tabel_A as a
I recommend using exists:
select a.name,
(exists (select 1
from tableB b
where a.id = b.id_tabel_A
)
) as status
from tableA a;
The reason I prefer exists is that it automatically handles duplicates in tableB. You don't have to worry about the query returning duplicate results.

need to merge rows into two colums mysql

please advice how to make SQL query in order to get from this table
ID|Number|Type|
----------------
1 |AA1 |IN |
2 |AA2 |OUT |
3 |AA3 |IN |
4 |AA4 |OUT |
into this result
ID| IN | OUT |
-------------------
1 | AA1 | AA2 |
2 | AA3 | AA4 |
Thanks
This Will work using Implicit join.
It will use mysql session variables. for reference, you can read http://www.mysqltutorial.org/mysql-variables/ for session variables.
SET #row_number = 0;
SET #row_number2 = 0;
SELECT
out_table.OUTs AS outs, in_table.Ins as INs FROM
(SELECT
(#row_number2:=#row_number2 + 1) AS num2, Number as OUTs FROM your_table WHERE your_table.Type = 'OUT') as out_table ,
(SELECT
(#row_number:=#row_number + 1) AS num1, Number as Ins FROM your_table WHERE your_table.Type = 'IN') as in_table
WHERE num2 = num1
You can emulate row_number like functionality, using session variables. We get all INs and OUTs separately in two derived tables and do a LEFT JOIN on them, to get the desired output.
This will work even for the cases where IN and OUT are not consecutive. It will also handle the cases where there is an IN without OUT.
It would not work for the case when there is an OUT without IN.
Try the following query:
SET #row_no_1 = 0;
SET #row_no_2 = 0;
SELECT
t1.row_no AS ID, t1.Number AS `IN`, t2.Number AS `OUT`
FROM
(SELECT
#row_no_1:=#row_no_1 + 1 AS row_no, Number
FROM
`your_table`
WHERE
Type = 'IN'
ORDER BY id ASC) AS t1
LEFT JOIN
(SELECT
#row_no_2:=#row_no_2 + 1 AS row_no, Number
FROM
`your_table`
WHERE
Type = 'OUT'
ORDER BY id ASC) AS t2 ON t2.row_no = t1.row_no
answering myself...
SELECT a.ID
MAX(CASE WHEN a.type = "IN" THEN a.Number ELSE "" END) AS IN_Type,
MAX(CASE WHEN b.type = "IN" THEN b.Number ELSE "" END) AS Out_Type
FROM table1 a Left join table1 b on a.ID = b.ID
Group by a.ID

MySQL subtract two count columns

I have a table like this:
client msg_type msg_body id
------ -------- -------- ---
123 typeA success abc
123 typeB success abc
456 typeA success abc
456 typeB failure abc
123 typeA success abc
123 typeA success abc
789 typeA success def
789 typeB success def
etc.
I would like output like this:
client diff id
------ ---- ---
123 2 abc
456 1 abc
789 0 def
where diff is the count of typeA:success messages - typeB:success messages. I can get the count of the typeA success using something like:
select client, count(*) from mytable
where msg_type="typeA" and msg_body="success"
However, I can't figure out how to put another count in there (for typeB) and also subtract.
I tried something like:
select client, count(*) from mytable
where msg_type="typeA" and msg_body="success" - count(*)
from mytable where msg_type="typeB" and msg_body="success"
But of course it didn't work, or I wouldn't be asking here. :) Any advice?
Edit: added another column. I tried the two suggestions given, but it only seems to return the results for one of the ids, not both.
Edit #2: I tried wrapping the SELECT query with:
select id, count(*) from (select ...) as anothertable where count_a_minus_count_b = 0;
I was hoping the output would be like:
id count
--- -----
abc 2
def 1
where count is the number of clients where the difference between typeA:success and typeB:success is 0.
COUNT counts non-null values, so you can construct an expression that's non-null when msg_type = 'typeA', and an expression that's non-null when msg_type = 'typeB'. For example:
SELECT client,
COUNT(CASE WHEN msg_type = 'typeA' THEN 1 END) AS count_a,
COUNT(CASE WHEN msg_type = 'typeB' THEN 1 END) AS count_b,
COUNT(CASE WHEN msg_type = 'typeA' THEN 1 END)
- COUNT(CASE WHEN msg_type = 'typeB' THEN 1 END) AS count_a_minus_count_b
FROM mytable
WHERE msg_body = 'success'
GROUP
BY client
;
(Disclaimer: not tested.)
Another way:
SELECT
d.client, COALESCE(a.cnt, 0) - COALESCE(b.cnt, 0) AS diff, d.id
FROM
( SELECT DISTINCT client, id
FROM mytable
) AS d
LEFT JOIN
( SELECT client, COUNT(*) AS cnt, id
FROM mytable
WHERE msg_type = 'typeA'
AND msg_body = 'success'
GROUP BY client, id
) AS a
ON d.client = a.client
AND d.id = a.id
LEFT JOIN
( SELECT client, COUNT(*) AS cnt, id
FROM mytable
WHERE msg_type = 'typeB'
AND msg_body = 'success'
GROUP BY client, id
) AS b
ON d.client = b.client
AND d.id = b.id ;
Tested at SQL-Fiddle
Here you go:
select client,
(sum(case when msg_type='typeA' and msg_body='success' then 1 else 0 end) -
sum(case when msg_type='typeB' and msg_body='success' then 1 else 0 end)) as diff
from your_table
group by client
Here's one way to get the result:
SELECT t.client
, SUM(t.msg_type<=>'typeA' AND t.msg_body<=>'success')
- SUM(t.msg_type<=>'typeB' AND t.msg_body<=>'success') AS diff
FROM mytable t
GROUP BY t.client
(The expressions in this query are MySQL specific; for a more portable query, use a less concise CASE expression to obtain an equivalent result.)
As more terse and obfuscated alternative to return the same result:
SELECT t.client
, SUM((t.msg_body<=>'success')*((t.msg_type<=>'typeA')+(t.msg_type<=>'typeB')*-1)) AS diff
FROM mytable t
GROUP BY t.client

increase query performance in mysql

I have used this query
SELECT COUNT(CASE WHEN C <= 1 THEN 1 END) AS nooffamiliesHavingcount1,
COUNT(CASE WHEN C BETWEEN 2 AND 4 THEN 1 END) AS nooffamiliesHavingcountbetween2And4,
COUNT(CASE WHEN C > 4 THEN 1 END) AS nooffamiliesHavingcountgreaterthan3
FROM ( SELECT COUNT(*) AS C
FROM user where user_id = (select user_id from location where location_id in(select location_id from country where state_name='STATE'))
GROUP BY House_No
) t
Here sub query returning approximately 10000 records . The user
table has 10,00,000 records. It is taking too much time.Then the
error it is saying is server gone away. I am using mysql.
I searched from google.But no luck for me.
What changes i need to do for my tables.How i can execute this query successfully by
increasing the query performance.Please suggest me.Thanks in advance....
Try this query
SELECT
COUNT(CASE WHEN C <= 1 THEN 1 END) AS nooffamiliesHavingcount1,
COUNT(CASE WHEN C BETWEEN 2 AND 4 THEN 1 END) AS nooffamiliesHavingcountbetween2And4,
COUNT(CASE WHEN C > 4 THEN 1 END) AS nooffamiliesHavingcountgreaterthan3
FROM
(SELECT
COUNT(*) AS C
FROM
user u,
location l,
country c
where
l.state_name='STATE' AND
l.some_other_column_id= 4 AND <------- Add your condition
c.location_id = l.location_id AND
u.user_id = l.user_id
GROUP BY
u.House_No) t
Use proper joins as it will be easy to understand..
SELECT
COUNT(CASE WHEN C <= 1 THEN 1 END) AS nooffamiliesHavingcount1,
COUNT(CASE WHEN C BETWEEN 2 AND 4 THEN 1 END) AS nooffamiliesHavingcountbetween2And4,
COUNT(CASE WHEN C > 4 THEN 1 END) AS nooffamiliesHavingcountgreaterthan3
FROM
(SELECT
COUNT(*) AS C
FROM
user u
INNER JOIN
location l
ON
l.state_name='STATE' AND
l.some_other_column_id= 4 <------- Add your condition
u.user_id = l.user_id
INNER JOIN
country c
ON
c.location_id = l.location_id
GROUP BY
u.House_No) t
EDITED
In most cases JOINs are faster than sub-queries and it is very rare for a sub-query to be faster.
I accept using subquery is more logical and easy to understand but when it comes about performance it is not as good as joins.
If you are using joins your db will optimize your query on its own which is not in the case of subquery.
Try using explain for both of your query and you will get clear idea how the query executes.
Hope this helps...
Can you try below:
SELECT COUNT(CASE WHEN COUNT() <= 1 THEN 1 END) AS nooffamiliesHavingcount1,
COUNT(CASE WHEN COUNT() BETWEEN 2 AND 4 THEN 1 END) AS nooffamiliesHavingcountbetween2And4,
COUNT(CASE WHEN COUNT(*) > 4 THEN 1 END) AS nooffamiliesHavingcountgreaterthan3
FROM User user
Inner JOIN
(select user_id from location loc
Inner Join country con
on loc.location_id =con.location_id where state_name='STATE' )as temp
on user.user_id =temp.user_id group by House_No

SQL: finding differences between rows

I want to count how many times each user has rows within '5' of eachother.
For example, Don - 501 and Don - 504 should be counted, while Don - 501 and Don - 1600 should not be counted.
Start:
Name value
_________ ______________
Don 1235
Don 6012
Don 6014
Don 6300
James 9000
James 9502
James 9600
Sarah 1110
Sarah 1111
Sarah 1112
Sarah 1500
Becca 0500
Becca 0508
Becca 0709
Finish:
Name difference_5
__________ _____________
Don 1
James 0
Sarah 2
Becca 0
Use the ABS() function, in conjunction with a self-join in a subquery:
So, something like:
SELECT name, COUNT(*) / 2 AS difference_5
FROM (
SELECT a.name name, ABS(a.value - b.value)
FROM tbl a JOIN tbl b USING(name)
WHERE ABS(a.value - b.value) BETWEEN 1 AND 5
) AS t GROUP BY name
edited as per Andreas' comment.
Assuming that each name -> value pair is unique, this will get you the count of times the value is within 5 per name:
SELECT a.name,
COUNT(b.name) / 2 AS difference_5
FROM tbl a
LEFT JOIN tbl b ON a.name = b.name AND
a.value <> b.value AND
ABS(a.value - b.value) <= 5
GROUP BY a.name
As you'll notice, we also have to exclude the pairs that are equal to themselves.
But if you wanted to count the number of times each name's values came within 5 of any value in the table, you can use:
SELECT a.name,
COUNT(b.name) / 2 AS difference_5
FROM tbl a
LEFT JOIN tbl b ON NOT (a.name = b.name AND a.value = b.value) AND
ABS(a.value - b.value) <= 5
GROUP BY a.name
See the SQLFiddle Demo for both solutions.
Because the OP also wants de zero counts, we'll need a self- left join. Extra logic is needed if one person has two exactly the same values, these should also be counted only once.
WITH cnts AS (
WITH pair AS (
SELECT t1.zname,t1.zvalue
FROM ztable t1
JOIN ztable t2
ON t1.zname = t2.zname
WHERE ( t1.zvalue < t2.zvalue
AND t1.zvalue >= t2.zvalue - 5 )
OR (t1.zvalue = t2.zvalue AND t1.ctid < t2.ctid)
)
SELECT DISTINCT zname
, COUNT(*) AS znumber
FROM pair
GROUP BY zname
)
, names AS (
SELECT distinct zname AS zname
FROM ztable
GROUP BY zname
)
SELECT n.zname
, COALESCE(c.znumber,0) AS znumber
FROM names n
LEFT JOIN cnts c ON n.zname = c.zname
;
RESULT:
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 14
zname | znumber
-------+---------
Sarah | 3
Don | 1
Becca | 0
James | 0
(4 rows)
NOTE: sorry for the CTE, I had not seen th mysql tag,I just liked the problem ;-)
SELECT
A.Name,
SUM(CASE WHEN (A.Value < B.Value) AND (A.Value >= B.Value - 5) THEN 1 ELSE 0 END) Difference_5
FROM
tbl A INNER JOIN
tbl B USING(Name)
GROUP BY
A.Name