MySQL GROUP BY "and filter" - mysql

Let's say i have query like this:
SELECT name, GROUP_CONCAT(number)
FROM objects
GROUP BY name
And it outputs:
+----------+----------------------+
| NAME | GROUP_CONCAT(NUMBER) |
+----------+----------------------+
| false_1 | 2,1 |
| false_2 | 3,4 |
| true_1 | 4,3,2,1 |
| true_2 | 2,3 |
+----------+----------------------+
Now how can i return rows having 2 AND 3 as number?
Note: This query is grouped - table has 10 rows, like so:
+---------+--------+
| NAME | NUMBER |
+---------+--------+
| true_1 | 1 |
| true_1 | 2 |
| true_1 | 3 |
| ... | ... |
+---------+--------+
[Link to SQLFiddle]

SELECT name, GROUP_CONCAT(number)
FROM objects
WHERE number IN (2,3)
GROUP BY name
HAVING COUNT(*) = 2
SEE SQLFiddle Demo
or if you want to retain all value on which the name has,
SELECT a.name, GROUP_CONCAT(A.number)
FROM objects a
INNER JOIN
(
SELECT name
FROM objects
WHERE number IN (2,3)
GROUP BY name
HAVING COUNT(*) = 2
) b ON a.Name = b.Name
GROUP BY a.name
SEE SQLFiddle Demo

Related

MYSQL Concatenate columns without grouping

I have a single table containing country codes, and language ids
+------+------+-------------+
| id | iso | language_id |
+------+------+-------------+
| 1 | US | 4 |
| 2 | IE | 1 |
| 3 | DE | 2 |
| 4 | SG | 1 |
| 5 | FR | 3 |
| 6 | UK | 1 |
| 7 | AT | 2 |
+------+------+-------------+
What I need is a MySQL statement that will return a result set containing EVERY ISO and a concatenated string of ids where the language id matches
So in the example above, I am looking to get
+------+------+----------+
| id | iso | id_group |
+------+------+----------+
| 1 | US | 4 |
| 2 | IE | 2,4,6 |
| 3 | DE | 3,7 |
| 4 | SG | 2,4,6 |
| 5 | FR | 5 |
| 6 | UK | 2,4,6 |
| 7 | AT | 3,7 |
+------+------+----------+
My best attempt so far is shown below and in the sqlfiddle link, but the grouping is excluding some of the ISO's. I need to return every row
SELECT iso, language_id, GROUP_CONCAT(id) as id
FROM countries
GROUP BY language_id
http://sqlfiddle.com/#!9/907618/3
Can this be done with MySQL or will I need to run many statements to get the results?
Thanks
This query will return all ID for every language ID:
select language_id, GROUP_CONCAT(id ORDER BY id) as id_group
from countries
group by language_id
then you just have to join this query with the countries table:
select
c.id,
c.iso,
g.id_group
from
countries c inner join (
select language_id, GROUP_CONCAT(id ORDER BY id) as id_group
from countries
group by language_id
) g on c.language_id = g.language_id
order by
c.id
Without a subquery you could use a self-join:
select
c.id,
c.iso,
group_concat(c1.id order by c1.id) as id_group
from
countries c inner join countries c1
on c.language_id = c1.language_id
group by
c.id,
c.iso

How to select bi-directional mapped rows from a table in MySQL?

I have the MySQL table called table.
| ID |item_code| item_name |
| 1 | 12345 | abc |
| 2 | 12345 | xyz |
| 3 | 11221 | abc |
| 4 | 19261 | www |
| 5 | 12345 | abc |
| 6 | 62898 | abc |
| 7 | 92648 | xxx |
| 8 | 45678 | xxx |
| 9 | 1234 | pqrs |
| 10 | 2345 | defg |
| 11 | 1234 | pqrs |
I want the query which will results the below table:
> |item_code | item_name |
> | 12345 | abc |
> | 12345 | xyz |
> | 11221 | abc |
> | 62898 | abc |
> | 92648 | xxx |
> | 45678 | xxx |
I want the result considering of:
item_code mapped to multiple item_name. Here item_code 12345 is mapped with abc and xyz. item_code 1234 is mapped to pqrs.
item_name mapped to multiple item_code. Here item_name abc is mapped with three items: 12345,11221,62898. item_name xxx is mapped to 92648 and 45678.
Here is the SQL statement I tried:
(select a.item_code,a.item_name from table a
join ( select item_code
from table
group by item_code
having count(*) > 1 ) b
on a.item_code = b.item_code)
union
(select a.item_code,a.item_name from table a
join ( select Item_name
from table
group by Item_name
having count(*) > 1 ) b
on a.Item_name = b.Item_name);
But this SQL query does not generate the bi directional mapped keys. Can someone help me generate these bi-directional mappings?
SELECT DISTINCT t.item_code, t.item_name
FROM mytable t
INNER JOIN
(SELECT item_code, COUNT(DISTINCT item_name) num FROM mytable GROUP BY item_code) code
ON (t.item_code = code.item_code)
INNER JOIN
(SELECT item_name, COUNT(DISTINCT item_code) num FROM mytable GROUP BY item_name) name
ON (t.item_name = name.item_name)
WHERE code.num > 1 OR name.num > 1
The subqueries used in the two JOIN clauses are used to attach the counts for which each item code or name is repeated. The joined result set is filtered using the WHERE clause at the outermost level to include only those DISTINCT combinations where the code and/or the name was associated with multiple values for the opposite field.

How to find the sum of a temporary column in SQL?

I have this code:
SELECT ID, Name, 100 AS TempColumn
FROM MyTable;
And the table is this:
| ID | Name | TempColumn|
-------------------------
| 1 | A | 100 |
-------------------------
| 2 | B | 100 |
-------------------------
| 3 | C | 100 |
-------------------------
| 1 | A | 100 |
-------------------------
| 4 | D | 100 |
-------------------------
Now I want to find the sum of the |TempColumn| where ID=1.
So it should look like this:
| ID | Name | TempColumn|
-------------------------
| 1 | A | 200 |
-------------------------
How can I query this?
You can sum a constant:
SELECT ID, Name, SUM(100) AS SumOfTempColumn
FROM MyTable
WHERE ID = 1
GROUP BY ID, Name;
Example on SQL Fiddle
Should this not be reasonably straight forward using an aggregate query?
SELECT ID,
Name,
SUM(100) AS TempColumn
FROM MyTable
GROUP BY ID, Name;
SELECT ID, Name,SUM(TempColumn) AS TempColumn
FROM Table
WHERE ID = 1
GROUP BY ID, Name

Sort GROUP BY agregats

Imagine this table t1,
+----------+-------+--------+
| group_id | name | age |
+----------+-------+--------+
| 1 | A1 | 1 |
| 1 | A2 | 2 |
| 1 | A3 | 3 |
| 2 | B1 | 4 |
+----------+-------+--------+
Using the following query in MySQL,
SELECT group_id, name, COUNT(*) FROM t1 GROUP BY group_id
we get,
+----------+-------+--------+----------+
| group_id | name | age | COUNT(*) |
+----------+-------+--------+----------+
| 1 | A1 | 2 | 3 |
| 2 | B1 | 4 | 1 |
+----------+-------+--------+----------+
As you can see here, it's possible that values name=A1 and age=2 are not from the same record.
My question is, how can I control which single results form the name and age columns are shown, so the content is from one record? Is there a way to sort them in some way? Fro example sorting by age in reverse order would give
+----------+-------+--------+----------+
| group_id | name | age | COUNT(*) |
+----------+-------+--------+----------+
| 1 | A3 | 3 | 3 |
| 2 | B1 | 4 | 1 |
+----------+-------+--------+----------+
Thanks.
I don't know why do you say that your query works. You should also group by name...
SELECT group_id, name, COUNT(*) FROM t1 GROUP BY group_id, name
If you want to get only one of them, try:
SELECT group_id, MIN(name), COUNT(*) FROM t1 GROUP BY group_id
I don't know about full control, but you can do like this
SELECT student_name, MIN(test_score), MAX(test_score)
FROM student
GROUP BY student_name;
SELECT group_id, name, COUNT(*)
FROM t1
WHERE name IN ( 'xxx', 'yyy', ..., 'zzz' )
GROUP BY group_id
SORT BY COUNT(*)

MySQL SELECT value before MAX

How to select 1st, 2nd or 3rd value before MAX ?
usually we do it with order by and limit
SELECT * FROM table1
ORDER BY field1 DESC
LIMIT 2,1
but with my current query I don't know how to make it...
Sample table
+----+------+------+-------+
| id | name | type | count |
+----+------+------+-------+
| 1 | a | 1 | 2 |
| 2 | ab | 1 | 3 |
| 3 | abc | 1 | 1 |
| 4 | b | 2 | 7 |
| 5 | ba | 2 | 1 |
| 6 | cab | 3 | 9 |
+----+------+------+-------+
I'm taking name for each type with max count with this query
SELECT
`table1b`.`name`
FROM
(SELECT
`table1a`.`type`, MAX(`table1a`.`count`) AS `Count`
FROM
`table1` AS `table1a`
GROUP BY `table1a`.`type`) AS `table1a`
INNER JOIN
`table1` AS `table1b` ON (`table1b`.`type` = `table1a`.`type` AND `table1b`.`count` = `table1a`.`Count`)
and I want one more column additional to name with value before max(count)
so result should be
+------+------------+
| name | before_max |
+------+------------+
| ab | 2 |
| b | 1 |
| cab | NULL |
+------+------------+
Please ask if something isn't clear ;)
AS per your given table(test) structure, the query has to be as follows :
select max_name.name,before_max.count
from
(SELECT type,max(count) as max
FROM `test`
group by type) as type_max
join
(select type,name,count
from test
) as max_name on (type_max.type = max_name.type and count = type_max.max )
left join
(select type,count
from test as t1
where count != (select max(count) from test as t2 where t1.type = t2.type)
group by type
order by count desc) as before_max on(type_max.type = before_max .type)