Select count of different flags in a column in MySQL - mysql

I have a table:
id flag
1 Y
1 Y
1 Y
1 N
1 N
2 Y
2 N
2 N
3 Y
3 N
i want to do as select statement which will give me the following output.
id count_flag_Y count_flag_N
1 3 2
2 1 2
3 1 1
I was trying using the select case method but getting syntax error.
SELECT id,SUM(CASE WHEN flag= 'Y') as count_flag_Y,
SUM(CASE WHEN flag= 'N') as count_flag_N
from tablename
GROUP BY id
Is there any way to do it?

Your query was not far off, you only have a slight problem with the CASE expressions. Try this:
SELECT id,
SUM(CASE WHEN flag= 'Y' THEN 1 ELSE 0 END) AS count_flag_Y,
SUM(CASE WHEN flag= 'N' THEN 1 ELSE 0 END) AS count_flag_N
FROM tablename
GROUP BY id

You are very close, but in MySQL the CASE is not needed:
SELECT id, SUM(flag = 'Y') as count_flag_Y,
SUM(flag = 'N') as count_flag_N
FROM tablename
GROUP BY id;
MySQL treats boolean expressions like integers in a numeric context, with "1" for true and "0" for false.

Related

Query to display distinct combination and then display count for each distinct combination

There is a transid field for which multiple rows will exist in this table with a list of config values. For all the transid's, I would like to retrieve all the distinct combination of transid, config_name and value fields that exist in the table group by count
I have join query which is not returning the result as expected. Below is the table structure, query used, result and expected result
Table
transid config_name value
1 payment_fee instant
2 eligible_account true
1 Block_intl_trans false
5 payment_fee provider_charge
1 eligible_account false
1 KycEligible 0
2 KycEligible 1
5 KycEligible 1
5 Block_intl_trans true
2 Block_intl_trans false
2 payment_fee provider_charge
5 eligible_account true
The above table structure implies that below are the combination of configuration values for each user.
transid KycEligible payment_fee eligible_account Block_intl_trans
1 0 instant false false
2 1 provider_charge true false
5 1 provider_charge true false
Below is the query that I used to Convert rows to columns and then group them per config_name(For every config_name, instead of multiple rows for each config key and value combination). Then select all distinct combination of KycEligible, configname and value combination that are present in the table and count of each distinct combination.
select
distinct
max(case when b.config_name = 'KycEligible' then b.config_value end) KycEligible,
max(case when b.config_name = 'payment_fee' then b.config_value end) payment_fee,
max(case when b.config_name = 'eligible_account' then b.config_value end) eligible_account,
max(case when b.config_name = 'Block_intl_trans' then b.config_value end) Block_intl_trans,
count(*) AS COUNT
from tableA b
where b.config_name in ('KycEligible', 'payment_fee', 'eligible_account', 'Block_intl_trans')
group by b.config_name
having count(*) > 1
Expected Result:
KycEligible payment_fee eligible_account Block_intl_trans Count
0 instant false false 1
1 provider_charge true false 2
My query is not returning the expected result. Can someone please help with this query?
I think you need something like this:
SELECT
KycEligible, payment_fee, eligible_account, Block_intl_trans, COUNT(*) CNT
FROM (
SELECT
(SELECT MAX(t0.config_value) FROM test t0 WHERE t0.config_name = 'KycEligible' AND t0.transid = t.transid) as KycEligible,
(SELECT MAX(t0.config_value) FROM test t0 WHERE t0.config_name = 'payment_fee' AND t0.transid = t.transid) as payment_fee,
(SELECT MAX(t0.config_value) FROM test t0 WHERE t0.config_name = 'eligible_account' AND t0.transid = t.transid) as eligible_account,
(SELECT MAX(t0.config_value) FROM test t0 WHERE t0.config_name = 'Block_intl_trans' AND t0.transid = t.transid) as Block_intl_trans
FROM
test t
GROUP BY t.transid
) dt
GROUP BY KycEligible, payment_fee, eligible_account, Block_intl_trans
;
This would give the following:
ycEligible payment_fee eligible_account Block_intl_trans CNT
0 instantâ—‹ false false 1
1 provider_charge true false 1
1 provider_charge true true 1
The result differs from expected in question as:
2 and 5 transids have different Block_intl_trans
1 and 5 transids have different payment_fee
1 and 2 transids have different eligible_account
I'm giving two fiddle example because the example data you provide is not consistent.
This fiddle is for transid=5 with Block_intl_trans data is true - consistent with your table data example: https://www.db-fiddle.com/f/r1imsYP8dQxkLSo5SkYcVK/3
This fiddle is for transid=5 with Block_intl_trans data is false - consistent with the configuration combination that you illustrate: https://www.db-fiddle.com/f/r1imsYP8dQxkLSo5SkYcVK/4
I'm guessing the unique combination would be coming from all of the config_name values. Here is the example query:
SELECT KycEligible, payment_fee, eligible_account, Block_intl_trans, COUNT(*) FROM
(SELECT transid,
GROUP_CONCAT(CASE WHEN config_name="KycEligible" THEN config_value END) AS "KycEligible",
GROUP_CONCAT(CASE WHEN config_name="payment_fee" THEN config_value END) AS "payment_fee",
GROUP_CONCAT(CASE WHEN config_name="eligible_account" THEN config_value END) AS "eligible_account",
GROUP_CONCAT(CASE WHEN config_name="Block_intl_trans" THEN config_value END) AS "Block_intl_trans"
FROM TableA
GROUP BY transid) V
GROUP BY KycEligible, payment_fee, eligible_account, Block_intl_trans;
Simple query with Max,
count in result can be based on your input data (transid=5, config=Block_intl_trans, value=false or value=true)
SELECT KycEligible, payment_fee, eligible_account, Block_intl_trans, COUNT(*) FROM
(
SELECT
transid,
max(CASE WHEN config_name="KycEligible" THEN value END) AS "KycEligible",
max(CASE WHEN config_name="payment_fee" THEN value END) AS "payment_fee",
max(CASE WHEN config_name="eligible_account" THEN value END) AS "eligible_account",
max(CASE WHEN config_name="Block_intl_trans" THEN value END) AS "Block_intl_trans"
FROM <YOUR_TABLE_NAME>
GROUP BY transid
) tmp
GROUP BY KycEligible, payment_fee, eligible_account, Block_intl_trans;

group query result in which flag not included

I have a table like this
NAME FLAG
---------------------------
abc 1
abc 0
abc 2
def 1
def 2
xyz 0
xyz 0
xyz 1
efg 1
I need query that list the name (group the result) which flag not included 0 and included 1.The result simply like below:-
NAME FLAG
------------------
def 1
efg 1
I have tried the query but not results the same.
select * mytable where FLAG NOT IN (0) GROUP BY NAME;
This is the simplest solution I can come up with. I believe there are more elegant answers possible.
SELECT *
FROM mytable
WHERE name NOT IN (SELECT name FROM mytable WHERE flag = 0)
AND flag = 1;
You can use NOT EXISTS clause in this way.
select a.*
from tbl a
where not exists
(select *
from tbl b
where b.name=a.name
and b.flag=0)
and a.flag=1;
We can use aggregation. The trick is to run a condition on each row, and then use an aggregate function to pick out the net result of the condition from all of the rows...
SELECT t.name
FROM a_table_like_this t
GROUP BY t.name
HAVING MAX(t.flag=0) <> 1
AND MAX(t.flag=1) = 1
The expressions in the HAVING clause are MySQL shorthand.
A more ANSI standards compliant equivalent would be:
SELECT t.name
FROM a_table_like_this t
GROUP BY t.name
HAVING MAX( CASE WHEN t.flag=0 THEN 1 ELSE 0 END) <> 1
AND MAX( CASE WHEN t.flag=1 THEN 1 ELSE 0 END) = 1
To get a better handle on what this is doing, take a look at how those expressions are evaluated on each row. Remove the GROUP BY clause, and move those expressions into the SELECT list...
SELECT t.name
, t.flag
, CASE WHEN t.flag=0 THEN 1 ELSE 0 END AS `fl=0`
, CASE WHEN t.flag=1 THEN 1 ELSE 0 END AS `fl=1`
FROM a_table_like_this t
ORDER
BY t.name
, t.flag
We get something like
name flag fl=0 fl=1
------ ---- ---- ----
abc 1 0 1
abc 0 1 0
abc 2 0 0
def 1 0 1
def 2 0 0
xyz 0 1 0
xyz 0 1 0
xyz 1 0 1
efg 1 0 1
If we now aggregate these rows by name (GROUP BY name), we can use MAX() aggregate to pick out a 1 (if there's one in the group. Otherwise, we'll get back a 0.)
And we can do conditional tests on the results of aggregates functions in the HAVING clause.

How to get count of each value against unique id in Mysql

I Have below mentioned table:
Where Val column has 3 distinct value a,b & c.
ID Val
1 a
1 a
1 b
2 b
2 c
2 c
3 c
I want to get count of unique ids and count of ids for respective Val value (i.e a,b & c).
I am using query like this but it helps me to identify count for a single Val value at a time.
SELECT ID,COUNT(*)
FROM table1
WHERE Val='c' GROUP BY ID;
Required output:
ID count a b c
1 3 2 1 0
2 3 0 1 2
3 1 0 0 1
You can use group by and sum the count when val is equal to a,b or c. See below:
select id,
count(*) as `count`,
sum(case when val = 'a' then 1 else 0 end) as a,
sum(case when val = 'b' then 1 else 0 end) as b,
sum(case when val = 'c' then 1 else 0 end) as c
from yourTable
group by id;
Just use conditional aggregation:
select id, count(*), sum(val = 'a') as a, sum(val = 'b') as b, sum(val = 'c') as c
from table1
group by id;

Count by ratio and then group by MSQL

I have a table like
ID Name
1 ABC
1 DEF
1 VVV
1 BBB
1 BCD
2 ZZZ
2 BAA
3 AAA
3 BBB
3 BBC
I want to get the ratio of all the names that start with A to All the names that start with B group by ID.
So the output should be
ID Ratio
1 0.5
2 0
3 0.33
.
SELECT (ID, (SELECT COUNT(*) FROM `table` WHERE name LIKE 'A%') /
(SELECT COUNT(*) FROM `table` WHERE name LIKE 'B%')) AS `ratio` from table Group by ID
does not give me the right answer. It takes the total ratio of A/B across all ID's into account and writes that number for all the ID's.
I'd try:
SELECT ID, CASE WHEN B = 0 THEN 0 ELSE A/B END AS Ratio FROM
( SELECT ID,
SUM(CASE WHEN Name LIKE 'A%' THEN 1 ELSE 0 END) AS A,
SUM(CASE WHEN Name LIKE 'B%' THEN 1 ELSE 0 END) AS B
FROM my_table GROUP BY ID ) AS grouped;
The inner SELECT gets the group IDs, and for every ID, the number of items beginning with A and those beginning with B.
The outer SELECT (you can omit it if you're sure that there'll always be at least one B-row) checks that the ratio makes sense before attempting to calculate it.
Or else:
SELECT ID, COALESCE(SUM(CASE WHEN Name LIKE 'A%' THEN 1 ELSE 0 END)
/ SUM(CASE WHEN Name LIKE 'B%' THEN 1 ELSE 0 END), 0)
FROM my_table GROUP BY ID;
This takes advantage of the fact that, if the number of B-rows is zero, the division will yield NULL. The COALESCE transforms that NULL in a 0.
This will do it:
SELECT
id,
SUM(IF(name LIKE 'A%',1,0))/SUM(IF(name like 'B%',1,0))
FROM `table`
GROUP BY ID

Slow running query, is there a better way?

I've got a query that produces the right result, its just very slow. I feel like there must be a better way (perhaps without subqueries).
Table, result and query are below. I've anonymized the data and I have 8 subqueries rather than 2, but the format is the same.
Table "a":
id userId type amount
------------------------------------
1 1 a 400
2 1 b 300
3 1 c 230
4 2 a 600
5 2 b 500
6 2 c 430
I've got an index on each column and one additional one that encompasses the userId and type columns. I can also guarantee you that userId and type are unique (i.e. there would't be two type 'a' for user 1).
Desired Result:
userId typeAtotal typeBtotal
--------------------------------
1 400 300
2 600 500
My Query:
SELECT userId,
(SELECT amount
FROM a AS a2
WHERE a2.userId = a1.userId
AND a2.type = 'a') AS aAmt,
(SELECT amount
FROM a AS a3
WHERE a3.userId = a1.userId
AND a3.type = 'b') AS bAmt
FROM a AS a1
WHERE type IN ('a','b')
GROUP BY userId
Use:
SELECT t.userid,
MAX(CASE WHEN t.type = 'a' THEN amount ELSE NULL END) AS typeAtotal,
MAX(CASE WHEN t.type = 'b' THEN amount ELSE NULL END) AS typeBtotal
FROM YOUR_TABLE t
GROUP BY t.userid
If there can be more than one amount for either type - this will return the highest. If you want such situations added, use SUM:
SELECT t.userid,
SUM(CASE WHEN t.type = 'a' THEN amount ELSE NULL END) AS typeAtotal,
SUM(CASE WHEN t.type = 'b' THEN amount ELSE NULL END) AS typeBtotal
FROM YOUR_TABLE t
GROUP BY t.userid
Looks like cross-tabulation to me. You might try something like this:
SELECT userId,
SUM(IF(a.type = 'a'), a.amount, 0) AS aAmount,
SUM(IF(a.type = 'b'), a.amount, 0) AS bAmount
FROM a
WHERE type IN ('a', 'b')
GROUP BY a.userId
You might want to read this rather well-written tutorial: http://dev.mysql.com/tech-resources/articles/wizard/index.html
Edit: fixed the ELSE condition.