Get mysql result and count specific field - mysql

I have database result like this
ID | NAME | TYPE
--------------------
1 | baseball | 1
2 | kickball | 1
3 | football | 1
4 | soccer | 2
How do I do a select * so get all results but also get a total count of type = 2 in the results?
Any help appreciated.

This will give you the type count for the current row's type in each row:
select t1.*, t2.TypeCount
from Table1 t1
inner join (
select TYPE, count(*) as TypeCount
from Table1
group by TYPE
) t2 on t1.TYPE = t2.TYPE

Typically we manage to get this by the way of two distinct results set. However it is possible to get them all in one with a query similar to the following
SELECT ID, Name, Type
FROM MyTable
UNION
SELECT -1, Type, COUNT(*)
FROM MyTable
WHERE Type = 2
GROUP BY Type
ORDER BY ID
The assumption is that all normal IDs are > 0 allowing to the the -1 as a marker for the row with the count. This row will be first in the resultset, thanks to the ORDER BY.
Note that we could complicate things a bit and get a count for all types (or for several), by simply removing (or changing) the WHERE clause in the second query.

Related

Large Complex Query with UNION allows me to ORDER BY but not GROUP - why?

I have a large, complex query that combines multiple queries into a single output by using UNION.
It's essentially this:
SELECT *
FROM (SELECT query1.field1,
subquery.field1,
GROUP_CONCAT(DISTINCT subquery.field1 SEPARATOR ', ') AS 'Column3',
NULL AS 'Column4'
FROM (SELECT table1.field1, table1.field2, subquery1.field1
FROM table1
INNER JOIN (SELECT table2.field1
FROM table2) AS subquery1 ON table1.field1 = subquery.field1)
GROUP BY subquery.field1) AS query1
UNION
SELECT *
FROM (SELECT query1.field1,
subquery.field1,
GROUP_CONCAT(DISTINCT subquery.field1 SEPARATOR ', ') AS 'Column3',
NULL AS 'Column4'
FROM (SELECT table1.field1, table1.field2, subquery1.field1
FROM table1
INNER JOIN (SELECT table2.field1
FROM table2) AS subquery1 ON table1.field1 = subquery.field1)
GROUP BY subquery.field1) AS query2
ORDER BY field1
This is very very overly simplified (there are upwards of 15 subqueries in the whole thing). It IS returning the results set I want. If I split out each group and run the code for just "query1" or "query2", I get the correct results. The problem I'm running into is when I UNION them into a single results set.
Essentially, I want a set returned for Query1 and a set returned for Query2. But I want these grouped by person (the identifier is field1), so that each row belongs to only a single person and displays information in the columns for both query 1 AND query 2.
What I'm getting right now is the list of people, and if they meet both criteria, they get 2 lines. One for appearing in query1 and one for appearing in query2. Some people will appear in both, some people will only appear in one or the other.
I want to see:
column 1 | column 2 | column 3 | column 4
field 1 | field 2 | field 3 | field 4
What I'm getting instead is:
column 1 | column 2 | column 3 | column 4
field 1 | field 2 | field 3 | NULL
field 1 | field 2 | NULL | field 4
I can ORDER BY field1 so that it places these two lines together, but if I GROUP BY field1, I get a syntax error for unknown column.
I don't understand how it's a known column for ORDER BY but unknown for GROUP BY.

Can't get the right column value for a query containing max()

I have a set of data like :
Nm | item | type | value
21 | 19 | A | 15
22 | 40 | B | 10
21 | 20 | A | 80
32 | 40 | C | 40
I tried several queries and i always get : (for the record Nm = 21)
Nm | item | type | max(value)
21 | 19 | A | 80
which is not what i want ,since the max value is from the item = 20
select
* from table t1 where nm=21
order by value desc
limit 1
You need to find row which is having maximum value for particular nm. For that you need to lookup each nm and find maximum value in sub query and then compare that maximum value with main query.
Query:
select *
from item_table it_o
where it_o.value in
(select max(value)
from item_table it_i
where it_i.nm=it_o.nm)
Output:
nm item type value
22 40 B 10
21 20 A 80
32 40 C 40
SELECT Nm, item, type, value
FROM ( SELECT Nm, MAX( value ) AS value
FROM YourTable
GROUP
BY Nm ) AS m
NATURAL JOIN YourTable
WHERE Nm = 21;
I've been asked to provide an explanation so here goes:
First, you need to find the maximum value (you haven't given a table name so I'm going to use YourTable):
SELECT MAX( value ) AS value
FROM YourTable
WHERE item = 21
Second, you want to project all attributes which requires joining the table expression above back to YourTable but we can't do that because we haven't projected the Nm attribute.
It's tempting to think we can simply project the attribute:
SELECT Nm, MAX( value ) AS value
FROM YourTable
WHERE item = 21
However, this makes SQL barf. To make SQL happy we must say which columns we are summarizing by (no matter how obvious it is!) using SQL's rather clunky GROUP BY syntax:
SELECT Nm, MAX( value ) AS value
FROM YourTable
WHERE item = 21
GROUP
BY Nm
Now we can join back to YourTable but again things aren't so simple:
SELECT Nm, item, type, value
FROM ( SELECT Nm, MAX( value ) AS value
FROM YourTable
WHERE Nm = 21
GROUP
BY Nm )
NATURAL JOIN YourTable;
Again, SQL barfs because we haven't given our derived table a name. Now you may be wondering, what is the point of giving it a name if we are using NATURAL JOIN, of which one of its advantages over, say, INNER JOIN is that we don't need range variables? Well, there is no point, it is not needed. However, the SQL Standards declared it is required. Therefore, we are forced to include a name, pointless though it is:
SELECT Nm, item, type, value
FROM ( SELECT Nm, MAX( value ) AS value
FROM YourTable
WHERE Nm = 21
GROUP
BY Nm ) AS pointless_name
NATURAL JOIN YourTable;
Note my SQL code above is different: one applies one's experience to change the structure of the query to make it generally more useful (sorry, I don't have an explanation beyond intuition for this!).
You have to do order by item desc so max value come first then select only one row by doing limit 1
SELECT * FROM TABLE ORDER BY VALUE DESC LIMIT 1
or you can select max id in subquery and select that id in main query (this query can return multiple rows)
SELECT * FROM TABLE WHERE VALUE IN (SELECT MAX(VALUE) FROM TABLE)
You can try like this
select * from tablename where value = (SELECT MAX(value) FROM tablename )
OR
select top 1 * from tablename order by value desc
SELECT a.*
FROM YourTable a
JOIN
( SELECT nm
, MAX(value) value
FROM YourTable
GROUP
BY nm
) b
ON b.nm = a.nm
AND b.value = a.value

GROUP BY inverse (mysql)

Is there any way to get the inverse of a group by statement in mysql? My use case is to delete all duplicates.
Say my table looks like this:
ID | columnA | ...
1 | A
2 | A
3 | A
4 | B
5 | B
6 | C
I want my result set to look like this:
ID | columnA | ...
2 | A
3 | A
5 | B
(Essentially this finds all duplicates leaving one behind. Could be used to purge all duplicate records down to 1, or to perform other analysis later).
One way is to take all but the first id for each value of ColumnA:
select t.*
from t
where t.id > (select min(t2.id) from t t2 where t2.columnA = t.columnA);
Your result seems
select max(id), columnA group by columnA
This should perform a lot better then inner select based queries.
SELECT
*
FROM
TABLE
QUALIFY
RANK() OVER (partition by columnA order by ID ASC ) = 1
EDIT : This apparently wont work in MySQL. Guess the only answer is to by a oracle license - or use another answer. ;)
I realized my own solution based on #scaisEdge response before he edited it. In need the opposite of my group by, so using a subquery:
SELECT * FROM mytable WHERE ID NOT IN (SELECT ID FROM mytable GROUP BY columnA);
I am confident this will help.
create table test.temptable select distinct * from YourTable;
truncate YourTable;
insert into YourTable select * from test.temptable ;

MySQL - count values and merge results from multiple tables

I have two tables with one column each, containing names.
Names can have duplicates. One name can be found on every table or only in one.
I want to make an query that count duplicates, for each name in every table an list these values like this:
| name | table1 | table2 |
| john | 12 | 23 |
| mark | 2 | 5 |
| mary | | 10 |
| luke | 4 | |
I tried different strategies using UNION but no luck.
Thanks in advance!!!
SELECT DISTINCT t1.name, t1.cnt1, t2.cnt2
FROM
(SELECT name,count(name) as cnt1 FROM table1 GROUP BY name) t1
LEFT JOIN
(SELECT name,count(name) as cnt2 FROM table2 GROUP BY name) t2
ON t1.name = t2.name
UNION
SELECT DISTINCT t2.name, t1.cnt1, t2.cnt2
FROM
(SELECT name,count(name) as cnt1 FROM table1 GROUP BY name) t1
RIGHT JOIN
(SELECT name,count(name) as cnt2 FROM table2 GROUP BY name) t2
ON t1.name = t2.name
Here's a simpler solution:
You can UNION the names from the two tables together, manually differentiating their origin tables with a tbl column.
Then it's just a simple GROUP BY with conditional aggregation using the differentiating column:
SELECT a.name,
NULLIF(COUNT(CASE a.tbl WHEN 1 THEN 1 END), 0) AS table1,
NULLIF(COUNT(CASE a.tbl WHEN 2 THEN 1 END), 0) AS table2
FROM
(
SELECT name, 1 AS tbl FROM table1 UNION ALL
SELECT name, 2 FROM table2
) a
GROUP BY a.name
In accordance with your desired result-set, we NULL the count value if it turns out to be 0.
SQLFiddle Demo
SELECT SUM(res.cn), name
FROM
(
SELECT name, count(name) as cn from table1 GROUP BY name HAVING count(name) > 1
UNION ALL
SELECT name, count(name) as cn from table2 GROUP BY name HAVING count(name)>1
) as res
GROUP BY nam
e
Try the above :) I made a fiddle for you to test it:
http://sqlfiddle.com/#!3/796b2/3
It has a few double names in each table and will show you which names have doubles and then print them. The names that only appear once are not shown (acheived by the HAVING clause)
After some reading i don't think that it's posibil what i want to do. This situation ca be solved with pivot table in excel or libreoffice.
In fact this is method that i used, combined with some sql stataments to count occurence of names and export as CSV.
UNION definitetly not work. Some chance are with join, but not shure.
I found a post that discusses the same problem as mine.
MySQL - Rows to Columns

Retrieve Unique Values and Counts For Each

Is there a simple way to retrieve a list of all unique values in a column, along with how many times that value appeared?
Example dataset:
A
A
A
B
B
C
... Would return:
A | 3
B | 2
C | 1
Use GROUP BY:
select value, count(*) from table group by value
Use HAVING to further reduce the results, e.g. only values that occur more than 3 times:
select value, count(*) from table group by value having count(*) > 3
SELECT id,COUNT(*) FROM file GROUP BY id