Mysql Count multiple columns based on the same values - mysql

I have the following like table
A B
Yes OOS
No No
OOS Yes
OOS No
Yes No
I want to do the following
Criteria A B
Yes 2 1
No 1 3
OOS 2 1
I can get this right with one column like
Criteria A
Yes 2
No 1
OOS 2
Here is what I have to achieve the above:
SELECT A, count(A) FROM temp_db GROUP BY A;

For this sample data, you could do this with a join of derived tables:
SELECT qa.Criteria, qa.A, qb.B FROM
(SELECT A AS Criteria, count(A) AS A FROM temp_db GROUP BY A) qa
FULL OUTER JOIN
(SELECT B AS Criteria, count(B) AS B FROM temp_db GROUP BY B) qb
ON qa.Criteria=qb.Criteria
But if there are missing criteria in the A column, they will not appear in the results of this query, and you would need the UNION ALL approach others have suggested.

You need to get the values into a single column, so you can use group by. Here is one method:
select criteria, sum(A) as A, sum(B) as B
from ((select A as criteria, 1 as A, 0 as B
from liketable
) union all
(select B, 0, 1
from liketable
)
) t
group by criteria;
Using the union all approach is the safest way in MySQL, in case not all criteria are in both columns. The following is a slight tweak that might be a bit better performance-wise:
select criteria, sum(A) as A, sum(B) as B
from ((select A as criteria, count(*) as A, 0 as B
from liketable
group by A
) union all
(select B, 0, count(*)
from liketable
group by B
)
) t
group by criteria;
Often doing two aggregations on half the data is more efficient than a bigger aggregation on all the data.

select val, sum(cntA), sum(cntB)
from (SELECT A as val, count(A) as cntA, 0 as cntB FROM temp_db GROUP BY A;
union all
SELECT B as val, 0 as cntA, count(B) as cntB FROM temp_db GROUP BY B)
group by val;

Related

SQL AVG applied to more than one by group?

I am trying to calculate a column average by group for several groups in the same query.
Assume there are 2 columns (a,b), for each I want the average of another column (c) per group of the first column. For example, this would return the a groups and average c value per a group.
SELECT a, AVG(c)
FROM mytable
GROUP BY a
This gives me two columns.
a
AVG(c)
1
0.5
2
0.75
I want a table like with two columns per grouping column like this.
a
AVG(c)
b
AVG(c)
1
0.5
8
1.5
2
0.75
9
0.25
Thanks.
This is more simply done in separate rows with union all:
SELECT 'a' as which, a, AVG(c)
FROM mytable
GROUP BY a
UNION ALL
SELECT 'b' as which, b, AVG(c)
FROM mytable
GROUP BY b;
If you really want them side-by-side, the query is quite a bit more complicated:
SELECT MAX(a) as a, MAX(a_avg_c) as a_avg_c,
MAX(b) as b, MAX(b_avg_c) as b_avg_c
FROM ((SELECT a, AVG(c) as a_avg_c, null as b, null as b_avg_c,
ROW_NUMBER() OVER (ORDER BY a) as seqnum
FROM mytable
GROUP BY a
) UNION ALL
(SELECT null, null, b, AVG(c) as b_avc_c,
ROW_NUMBER() OVER (ORDER BY b) as seqnum
FROM mytable
GROUP BY b
)
) ab
GROUP BY seqnum;
This is more complicated because SQL treats a row as a single entity. You actually want columns on each row that are entirely unrelated to each other. So, this version creates a "relation" by assigning a sequential value and then aggregating by that value to get what you want.
You can use analytical function and distinct as follows:
Select distinct a,
Avg(c) over (partition by a) as a_avg,
B,
Avg(c) over (partition by b) as b_avg
From your_table t

How do I find duplicate values across multiple columns in Mysql?

I have a table like this
I want to check the all rows in Column A with column B and get the count of duplicates.
For example, I want to get the
count of 12 as 3(2 times in A+1 time in B)
count of 11 as 2(2 times in A+0 time in B)
count of 13 as 2(1 time in A+0 time in B)
How can I acheive it?
You can calculate the total occurrences from a union all. A where clause can show only the values that occur in the A column:
select nr
, count(*)
from (
select A as nr
from YourTable
union all
select B
from YourTable
) sub
where nr in -- only values that occur at least once in the A column
(
select A
from YourTable
)
group by
nr
having count(*) > 1 -- show only duplicates
You can combine all values in A and B then do the group by.
Then only select those values found in column A.
Select A, count(A) as cnt
From (
Select A
from yourTable
Union All
Select B
from yourTable) t
Where t.A in
(select distinct A from yourTable)
Group by t.A
Order by t.A;
Result:
A cnt
11 2
12 3
13 1
See demo: http://sqlfiddle.com/#!9/9fcfe9/3

select max() from result of count for distinct ids in mysql

I have a table with the following structure:
id name
1 X
1 X
1 Y
2 A
2 A
2 B
Basically what I am trying to do is to write a query that returns X for 1 because X has repeated more than Y (2 times) and returns A for 2. So if a value occurs more than the other one my query should return that. Sorry if the title is confusing but I could not find a better explanation. This is what I have tried so far:
SELECT MAX(counted) FROM(
SELECT COUNT(B) AS counted
FROM table
GROUP BY A
) AS counts;
The problem is that my query should return the actual value other than the count of it.
Thanks
This should work:
SELECT count(B) as occurrence, A, B
FROM table
GROUP BY B
ORDER BY occurrence DESC
LIMIT 1;
Please check: http://sqlfiddle.com/#!9/dfa09/3
You can try like this using a GROUP BY clause. See a Demo Here
select *, max(occurence) as Maximum_Occurence from
(
select B, count(B) as occurence
from table1
group by B
) xxx
This is how I finally handled my problem. Not the most efficient way but get the job done:
select A,B from
(select A,B, max(cnt) from
(select A ,B ,count(B) as cnt
from myTable
group by A,B
order by cnt desc
) as x group by A
) as xx

UNION ignores column names?

Why does
select 1 as a, 2 as b
union all
select 20 as b, 10 as a
returns
a b
1 2
20 10
instead of
a b
1 2
10 20
?
Is there a way to make union match column names?
Nope, selecting them in order is required with UNION.
Column names are only pertinent for the first part of the union to deifne the union columns. Other unions will join in the same order the columns are given from the first select and often have differn names. If you want want to relate the first column to the second column, You can't. However you can adjust your second select statment to put the columns in the correct order.
Union only looks at the number of columns, and their relative positions in the query string. it does NOT mix-match based on aliases or the source column names. e.g. You could have two completely different tables:
SELECT x,y FROM foo
UNION
SELECT p,q FROM bar
What should MySQL do in this case? return a single row
x,y,p,q
because none of the column names match? Nope. That'd be incorrect.
I'm not sure if this solves your problem, but you can use subqueries within the union to put the columns in the "right" order:
(select a, b from (select 1 as a, 2 as b) t)
union all
(select a, b from (select 20 as b, 10 as a) t)
I realize the question is tagged MySQL, which doesn't support full outer join. If it did, you could do do the union all as:
select coalesce(t1.a, t2.a) as a, coalesce(t1.b, t2.b) as b
from (select 1 as a, 2 as b) t1 full outer join
(select 20 as b, 10 as a) t2
on 0 = 1;
You can do this in MySQL. This assumes that none of your values are never NULL:
select coalesce(t1.a, t2.a) as a, coalesce(t1.b, t2.b) as b
from (select 1 as a, 2 as b union all select NULL, NULL) t1 join
(select 20 as b, 10 as a union all select NULL, NULL) t2
on (t1.a is null or t2.a is null) and coalesce(t1.a, t2.a) is not null

How to address multiple columns as one in MySQL?

Columns a, b and c contain some values of the same nature. I need to select all the unique values. If I had just one column I'd use something like
SELECT DISTINCT a FROM mytable ORDER BY a;
but I need to treat a, b and c columns as one and gett all the unique values ever occurring among them.
As an example, let this be a CSV representation of mytable, the first row naming the columns:
a, b, c
1, 2, 3
1, 3, 4
5, 7, 1
The result of the query is to be:
1
2
3
4
5
7
UPDATE: I don't understand why do all of you suggest wrapping it in an extra SELECT? It seems to me that the answer is
(SELECT `a` AS `result` FROM `mytable`)
UNION (SELECT `b` FROM `mytable`)
UNION (SELECT `c` FROM `mytable`)
ORDER BY `result`;
isn't it?
So you want one column all with unique values from a, b and c? Try this:
(select a as yourField from d1)
union
(select b from d2)
union
(select c from d3)
order by yourField desc
limit 5
Working example
Edited after requirements changed... There you have the order by and limit you requested. Of course, you'll get only 5 records in this example
sorry i miss understood your question. here is updated query.
select a from my table
UNION
select b from my table
UNION
select c from my table
SELECT tmp.a
FROM
(SELECT column_1 AS a
FROM table
UNION
SELECT column_2 AS a
FROM table
UNION
SELECT column_3 AS a
FROM table) AS tmp
ORDER BY `tmp`.`a` ASC
try this:
SELECT b.iResult
FROM
(SELECT a as iResult FROM tableName
UNION
SELECT b as iResult FROM tableName
UNION
SELECT c as iResult FROM tableName) b
ORDER BY b.iResult
LIMIT BY 10 -- or put any number you want to limit.