SQL Filtering group data - mysql

i've got a DB like this
id name group
with data like this
1 john A
2 john B
3 charles B
4 peter B
5 rose B
6 charles A
7 justin C
As you can see, the posibilities are that one ID it's associated with one group, or more than one group
i need a query for filtering
a) are in group A and B
b) are in group A but not B
c) are only in group A

a. select distinct name from tablename where group = 'A' or group = 'B';
b. select distinct name from tablename where group = 'A' and group <> 'B';
c. select distinct name from tablename where group = 'A' and
group not in (select distinct(t1.group) from tablename t1
where t1.group <> 'A');

I like approaching these problems using group by and the having clause. For your first question:
select name
from table
group by name
having sum(group = 'A') > 1 and sum(group = 'B') > 0;
The other two are:
having sum(group = 'A') > 1 and sum(group = 'B') = 0;
having sum(group = 'A') > 1 and sum(group <> 'A') = 0;

Related

Show IDs where two conditions in the same column satisfy

This is my table1
ID || Basket || Balls
--------------------------
1 || Ram || 1
1 || Rom || 3
2 || Ram || 2
3 || Rom || 5
Query - Select all the IDs that have both at least 1 ball in both Ram and Rom.
----All the IDs that have at least 1 ball in Ram
SELECT distinct ID
INTO #RAM
FROM Table1
where balls > =1 and basket = 'Ram'
----All the IDs that have at least 1 ball in Rom
SELECT distinct ID
INTO #ROM
FROM Table1
where balls > =1 and basket = 'Rom'
---All the IDs that have both
Select distinct ID
INTO #FinalTable
from #RAM a join #ROM b on a.id = b.id
This is what I have written so far it works but I feel there is definitely a more efficient way to do this.
Please let me know. Thank you.
I would use a single aggregation:
select id
from table1 t1
group by id
having sum(case when basket = 'Ram' then balls end) > 0 and
sum(case when basket = 'Rom' then balls end) > 0;
Assuming the value of balls is never negative or zero, then you only need to check that that the rows exist. That is a little simpler in MySQL:
select id
from table1 t1
group by id
having sum(basket = 'Ram') > 0 and
sum(basket = 'Rom') > 0;
You can use subqueries to achieve this.
join RAM
join ROM
select count() >= 1
select t1.ID
from Table1 t1
join
(select ID, count(1) ct from Table1 where Basket = 'Ram'
group by ID) as ram on ram.ID = t1.ID
join
(select ID, count(1) ct from Table1 where Basket = 'Rom'
group by ID) as rom as rom.ID = t1.ID
where ram.ct >= 1 and rom.ct >= 1
You need Only t use this query and combine your Queries
SELECT
a.ID
FROM (SELECT ID FROM Table1 Where Balls >= 1 And Basket = 'RAM') a
INNER JOIN (SELECT ID FROM Table1 Where Balls >= 1 And Basket = 'ROM') b
ON a.ID = b.ID
It only return the OD that are have nmore than 1 ball and are in RoM and RAM
We can group by based on ID,Basket and select records having count greater than 1
select distinct a.id from
(
select id,basket,count(balls) as cn
from table1
group by id,basket
having cn>1
) a ;

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 group by for missing values

Given a table with the following data
ID Value
1 A
1 B
1 C
1 D
2 A
2 C
3 A
I would like to build a query that returns which values are missing from the id set based on value A being present. It can be assumed an ID for 'A' is always present.
Result:
ID | B | C | D
2 | 0 | 1 | 0
3 | 0 | 0 | 0
The values are A, B, C, D. In this example all values are there for ID 1 but the table reports that B is missing for both given that A is a value for ID 2 and so on.
I have a query to return which ID's are missing for a given value but I have not found a way to join all three together:
select id
from table_1
where id not in (
select id
from table_1
where value = 'B' #additional queries replacing 'B' with 'C' and 'D'
) and value = 'A'
order by id asc
Is it possible to combine those three separate queries in to a result table as I have laid out? I feel like this requires inner joins but have not been able to build out a query that works.
You could use conditional aggregation:
SELECT id,
SUM(Value = 'A') AS a,
SUM(Value = 'B') AS b,
SUM(Value = 'C') AS c,
SUM(Value = 'D') AS d
FROM tab
GROUP BY id;
DBFiddle Demo
Values list (A,B,C,D) has to be known in advance.
Skipping row if all values are present:
SELECT *
FROM (
SELECT id, SUM(Value = 'A') AS a,
SUM(Value = 'B') AS b,
SUM(Value = 'C') AS c,
SUM(Value = 'D') AS d
FROM tab
GROUP BY id
) sub
WHERE NOT (a>0 and b>0 and c>0 and d>0);
DBFiddle Demo2

SQL Query - Find Duplicates with a Different Key

I have the following data:
id userid name group
1 1 A x
2 1 A y
3 1 A z
4 2 B x
5 2 B y
6 3 C y
7 4 D x
8 5 E x
9 5 E z
10 6 F x
I want to find those records that meet all this condition:
Select all rows where the a userid belongs to a group other than y but the userid also belongs to group y.
The resulting dataset will be as follows:
id userid name group
1 1 A x
3 1 A z
4 2 B x
If you see, it has resulted in two records for userid a because these are two two records belong to groups other than y but the userid 1 also belongs to group y. Same for userid 2.
I have been breaking my head on how to get this in an SQL statement but not even close to a solution.
Any help is appreciated.
Use a join:
SELECT t1.*
FROM mytable t1
INNER JOIN mytable t2
ON t1.user_id = t2.user_id AND t1.group <> t2.group AND t2.group = 'y'
I think that would be the fastest query (but please feel free to try the other solutions as well).
Add an index on user_id if not already there and maybe play with some other indexes as well (maybe a composite index on group and user_id can be utilized)
Use exists
select *
from MyTable a2
where name_group <> 'y'
and exists (select 1
from MyTable a2
where a2.name_group = 'y'
and a2.userid = a1.userid)
You can get all the users that meet the condition using aggregation and having:
select userid
from t
group by userid
having sum( group = 'y' ) > 0 and
sum( group <> 'y') > 0;
I leave it to your to put this into a query to get all the original rows.

GROUP_CONCAT DISTINCT BY ID

I have 2 tables like this:
Table a:
ID type
1 1
1 1
2 1
2 2
2 2
3 2
Table b:
ID name
1 a
2 b
3 b
And expected result:
ID type name
1,2 1 a,b
2,3 2 b,b
I have tried:
SELECT GROUP_CONCAT(DISTINCT ID), a.type,
GROUP_CONCAT(SELECT name FROM b WHERE ID = a.ID)
FROM a GROUP BY a.type
but it's not working. I need name is GROUP_CONCAT and DISTINCT by ID.
I have found a solution for my question:
SELECT GROUP_CONCAT(DISTINCT a.id), a.type,
(SELECT GROUP_CONCAT(name) FROM b
WHERE FIND_IN_SET(ID, GROUP_CONCAT(a.ID)))
FROM a GROUP BY a.type
Try this one:
SELECT GROUP_CONCAT(DISTINCT a.id), a.type, GROUP_CONCAT(DISTINCT b.name)
FROM a
LEFT JOIN b ON a.id = b.id
GROUP BY a.type