SQL Query to check not repeated values - mysql

I'm new to SQL. I wanted to know, How to check the entries which are not repeated for the other entries.
Better I give one example.
column1
column2
a
1
a
2
a
3
a
4
b
1
b
2
b
3
b
4
c
1
c
2
c
3
I want output as
column1
column2
c
4
because c does not have 4, but the other values a and b do.

You are looking for missing entries. For these to find, you must know which entries you expect. You expect to find one entry for all combinations of column1 values and column2 values. You get these with a cross join.
Now you want to select all these pairs except for those already in the table. You can use EXCEPT for this or NOT EXISTS or NOT IN. You haven't told us your DBMS, so I don't know what it features.
EXCEPT
select c1.column1, c2.column2
from (select distinct column1 from mytable) c1
cross join (select distinct column2 from mytable) c2
except
select column1, column2
from mytable
order by column1, column2;
NOT IN
select c1.column1, c2.column2
from (select distinct column1 from mytable) c1
cross join (select distinct column2 from mytable) c2
where (c1.column1, c2.column2) not in
(
select column1, column2 from mytable
)
order by c1.column1, c2.column2;
NOT EXISTS
select c1.column1, c2.column2
from (select distinct column1 from mytable) c1
cross join (select distinct column2 from mytable) c2
where not exists
(
select null
from mytable
where mytable.column1 = c1.column1
and mytable.column2 = c2.column2
)
order by c1.column1, c2.column2;

Provided columns are not nullable
select distinct column1
from mytable t1
where exists (
select 1
from mytable t2
where t2.column2 <> t1.column2
and t1.column1 not in (
select t3.column1
from mytable t3
where t3.column2 = t2.column2
)
)

Related

How to get maximum value of value1 from table where value1 and value2 fields ignoring value2 field

I have table with column1 = date, column2 = A/B, column3 = id. I want result where latest date comparing to Id should be with B in column2, Ignore if A
Table
C1 C2 C3
10/6/19 A 1
12/6/19 B 1
13/6/19 A 2
09/6/19 A 3
03/6/19 B 1
04/6/19 B 2
12/6/19 B 4
03/6/19 A 5
06/6/19 B 3
Expected result
C3 1 - Valid . Because last value of latest date is B
C3 4 - Valid . Because last value of latest date is B
C3 3 - Invalid. Because last value of latest date is A
Use a correlated subquery
DEMO
select * from t1 a
where c1 =(select max(c1) from t1 b where a.c3=b.c3 )
and c2='B'
OUTPUT:
c1 c2 c3
2012-06-19 B 1
2012-06-19 B 4
Assumin c1 column is valid date You could try using a subquery for max(c1)
select *
from my_table m
inner join (
select id, max(c1) max_c1
from my_table
group by id
) t on t.max_c1 = m.c1 and m.c2='A' and t.id = m.id
Or if you need also the id not matching you coul append uisng UNION
select *
from my_table m
inner join (
select id, max(c1) max_c1
from my_table
group by id
) t on t.max_c1 = m.c1 and m.c2='A'
select *
from my_table m
inner join (
select id, max(c1) max_c1
from my_table
group by id
) t on t.max_c1 = m.c1 and m.c2='A' and t.id = m.id
union
select max(c1), c2, id
from my_table where id not in (
select id
from my_table m
inner join (
select id, max(c1) max_c1
from my_table
group by id
) t on t.max_c1 = m.c1 and m.c2='A'
select *
from my_table m
inner join (
select id, max(c1) max_c1
from my_table
group by id
) t on t.max_c1 = m.c1 and m.c2='A' and t.id = m.id
)
group by c2, id
If you just want the c3 values with an indicator, you can use aggregation:
select c3,
(case when group_concat(c2 order by c1 desc) like 'B,%'
then 'Valid'
else 'Invalid'
end) as flag
from t
group by c3;

MySQL select a set of columns with more than one variation in another column

table looks like this:
id group name
1 1 A
2 1 A
3 2 A
4 2 B
5 3 A
I want to select the rows with more than one distinct names in the same group. The result should be the following:
id group name
3 2 A
4 2 B
Any idea how do achieve this?
You can get the groups with aggregation:
select group
from t
group by group
having min(name) <> max(name);
You can get the original rows using join, in, or exists:
select t.*
from t
where t.group in (select group
from t
group by group
having min(name) <> max(name)
);
Note: group is a lousy name for a column because it is a SQL keyword and a MySQL reserved word.
You could do it with a correlated subquery:
SELECT t1.id, t1.group, t1.name
FROM mytable AS t1
WHERE EXISTS (
SELECT * FROM mytable t2
WHERE t2.group=t1.group AND t2.name <> t1.name
);
Or you could do it by counting distinct names in the group:
SELECT t1.id, t1.group, t2.name
FROM mytable AS t1
INNER JOIN (
SELECT t2.group FROM mytable AS t2
GROUP BY t2.group HAVING COUNT(DISTINCT t2.name) > 1
) AS t2 USING (group);

Joining three tables such that extra matches are discarded?

How can I write a query to give the results of three tables such that there's only one result per "line"?
The tables are:
T1 (ID, name, IP)
T2 (ID, date_joined)
T3 (ID, address, date_modified)
The relations are:
T1-T2 1:1, T1-T3 1:M - there can be many address rows per ID in T3.
What I want is a listing of all users with the fields above, but IF they have an address, I only want to record ONE (bonus would be if it is the latest one based on T3.date_modified).
So I should end up with exactly the number of records in T1 (happens to be equal to T2 in this case) and no more.
I tried:
select t.ID, t.name, t.IP, tt.ID, tt.date_joined, ttt.ID, ttt.address
from T1 t JOIN T2 tt ON (t.ID = tt.ID) JOIN T3 ttt ON (t.ID = ttt.ID)
And every sensible combination of LEFT, RIGHT, INNER, etc joins I could think of! I keep getting multiple duplicate because of T3
This query should work:
select
t1.ID, t1.name, t1.IP, t2.date_joined, t3x.address
from t1
join t2 on t1.ID = t2.id
left join (
select t3.*
from t3
join (
select id, max(date_modified) max_date
from t3
group by id
) max_t3 on t3.id = max_t3.id and t3.date_modified = max_t3.max_date
) t3x on t1.ID = t3x.id
First you do the normal join between t1 and t2 and then you left join with a derived table (t3x) that is the set of t3 rows having the latest date.
So T2 is actually not relevant here. You just need a way to join from T1 to T3 in a way that gets you at most one T3 row per T1 row.
One way of doing this would be:
select
T1.*,
(select address from T3 where T3.ID=T1.ID order by date_modified desc limit 1)
from T1;
This won't likely be very efficient, being a correlated subquery, but you may not care depending on the size of your dataset.
It's also only good for getting one column from T3, so if you had Address, City, and State, you'd have to figure out something else.
You can use sub query with Top 1 so that u get only one result from T3
here is a sample sql
select * into #T1 from(
select 1 ID
union select 2
union select 3) A
select * into #T2 from(
select 1 ID
union select 2
union select 3) A
select * into #T3 from(
select 1 ID, 'ABC' Address, getDate() dateModified
union select 1, 'DEF', getDate()
union select 3, 'GHI', getDate()) A
select *, (select top 1 Address from #T3 T3 where T3.ID= T1.ID order by datemodified desc) from #T1 T1
inner join #T2 T2 on T1.ID = T2.ID
Bonus :- you can also add order by dateModified desc to get the latest address

MySQL select count based on two rows data

Table column headers: n,t1,t2
entries :
1 A B
2 A C
3 B C
4 D E
5 B A
How do I count total number of rows each letter appears in t1 MINUS the number of rows they appear in t2 ? I need to do something like following 2 lines in 1 query :
select count(*) as val,t1 from table group by t1
select count(*) as val,t2 from table group by t2
Thanks,
Martin
Here is one way:
select t1, max(t1cnt) - max(t2cnt) as diff
from ((select t1, count(*) as t1cnt, 0 as t2cnt
from t
group by t1
) union all
(select t2, 0 as t1cnt, count(*) as t2cnt
from t
group by t2
)
) t
group by t1
Using the union all ensures that you get all possible values from both columns, even values that only appear in one column.
You can use the following query to get the result. This query first gets a list of all the distinct t1 and t2 values (this is the UNION query). Once you have the list of these values, then you can use a LEFT JOIN to the original queries that you posted:
select d.col, coalesce(totT1, 0) - coalesce(totT2, 0) Total
from
(
select t1 col
from entries
union
select t2 col
from entries
) d
left join
(
select count(*) totT1, t1
from entries
group by t1
) d1
on d.col = d1.t1
left join
(
select count(*) totT2, t2
from entries
group by t2
) d2
on d.col = d2.t2;
See SQL Fiddle with Demo

MAX on two columns in mysql

I wonder if there is better way to get max from column c1 and then max from column c2 for selected rows than
SELECT MAX(c1) , MAX(c2) FROM t GROUP BY c1 HAVING c1 = MAX(c1)
SELECT Max(t2.c1) as C1,
Max(t1.c2) as C2
FROM t t1
INNER JOIN (SELECT Max(c1) AS C1
FROM t) t2
ON t1.c1 = t2.c1
I'm not quite sure whether you want all distinct c1's or just the maximum.
If you want all c1's:
SELECT c1, MAX(c2) FROM t GROUP BY c1;
If you want only the maximum c1:
SELECT c1, c2 FROM t ORDER BY c1 DESC, c2 DESC LIMIT 1;
Just read your comment on hkutluay's response, this might be what you want:
select MAX(colName)
from
(select col1 as colName
from tableName
union
select col2
from tableName) subqueryName
I know mysql does not have CTE's; but because the question is also marked SQL, and the CTE is a reasonable clean solution for the subquery, for completeness here is a CTE-version:
WITH zmax AS (
SELECT MAX(v1) AS v1
FROM ztable
)
SELECT zt.v1
, MAX(zt.v2) AS v2
FROM ztable zt
JOIN zmax mx ON zt.v1 = mx.v1
GROUP BY zt.v1
;