Mysql: ignore 2 distinct columns from a table - mysql

I have 2 tables that are something like this:
Table1:
animal name color
cat bob red
dog bill blue
Table2:
animal name
cat bob
fish joe
I want to query all the data in table 1 except if they have the unique identity from table 2, so I would get dog bill blue, and not the cat, since it appears in table 2.
I did:
select t.animal, t.name, t.color
from Table1 as t, Table2 as t2
where NOT(t.animal = t2.animal AND
t.name = t2.name)
group by t.animal, t.name
Is there a more efficient way of doing this?

select t.animal, t.name, t.color
from Table1 as t
LEFT JOIN Table2 as t2 ON t.animal = t2.animal and t.name = t2.name
where table2.name is null
group by t.animal, t.name

A simple where not exists clause should do the trick:
select t1.animal, t1.name, t1.color
from Table1 t1
where not exists
(
select 1
from Table2 t2
where t2.animal = t1.animal
and t2.name = t1.name
)
You can also use the anti-join pattern:
select t1.animal, t1.name, t1.color
from Table1 t1
left outer join Table2 t2 on t1.animal = t2.animal and t1.name = t2.name
where t2.animal is null

SELECT * FROM table_one t1
WHERE t1.animal NOT IN
(SELECT animal FROM table_two)

Related

Select distinct pairs in SQL

For this table each column has distinct rows i.e count(Name) = count(Spouse_Name) = count(*)
Want to write a SQL query where pairs (Name and Spouse_Name) are distinct i.e Alex Sandra and Sandra Alex are same.
The output should be following:
Note: Self Inner Join if possible.
Untested:
select distinct t1.name, t1.spouse_name
from table t1
inner join table t2
on concat(t1.name, t1.spouse_name) = concat(t2.spouse_name, t2.name)
I couldn't find the table name in your post so I used the name table.
Assuming that name and spouse_name will never be equal in the same row you can use NOT EXISTS like this:
select t.*
from tablename t
where t.name < t.spouse_name
or not exists (
select 1 from tablename
where name = t.spouse_name and spouse_name = t.name
)
This code will work in any database since it uses standard SQL.
For MySql and this sample data you can do this self join:
select distinct
least(t1.name, t1.spouse_name) name,
greatest(t1.name, t1.spouse_name) spouse_name
from tablename t1 inner join tablename t2
on t1.name = t2.spouse_name and t2.name = t1.spouse_name
Although the same results can be obtained without a join:
select distinct
least(t1.name, t1.spouse_name) name,
greatest(t1.name, t1.spouse_name) spouse_name
from tablename t1
And another query with a self join:
select t1.name, t1.spouse_name
from tablename t1 inner join tablename t2
on t2.spouse_name = t1.name and t2.name = t1.spouse_name
where t1.name < t1.spouse_name

postgres array_agg with distinct on json_build_object

select
t1.id,
array_agg(
json_build_object('id', t2.id, 'status', t2.status)
) as statuses
from table1 t1
inner join table2 t2 on t1.id=t2.user_id
inner join table3 t3 on t1.id=t3.user_id
group by t1.id
table1
id , user
1 , 'A'
2 , 'B'
table2
user_id , status
1 , 'P'
1 , 'AP'
table3
user_id , something
1 , 'A12'
1 , 'B1212'
the table3 also one-many relationship as a result the duplication of statuses coming in the array_agg,
i tried with array_agg(distinct json_build_object()) and array_agg(distinct on json_build_object()),
how can we prevent duplications in this case ??
Just filter out the relevant status as join condition (1):
select
t1.id,
array_agg(
json_build_object('id', t2.id, 'status', t2.status)
) as statuses
from table1 t1
inner join table2 t2 on t1.id=t2.user_id
inner join table3 t3 on t1.id=t3.user_id
and t3.status = 'A12' -- 1.
group by t1.id
Furthermore, if you want to get valid JSON arrays, you should use json_agg() instead of array_agg():
select
t1.id,
json_agg(
json_build_object('id', t2.id, 'status', t2.status)
) as statuses
from table1 t1
inner join table2 t2 on t1.id=t2.user_id
inner join table3 t3 on t1.id=t3.user_id
and t3.status = 'A12'
group by t1.id

SQL: full outer join (ambitious column name)

I have two table, t1 and t2.
-- t1
id name address
1 Tim A
2 Marta B
-- t2
id name address
1 Tim A
3 Katarina C
If I do t1 full outer join with t2
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
However, the result has ambitious id, name, address.
How do I rename this so that I don't have duplicate column name?
Attempt:
SELECT name, address FROM
(SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id) as derived_table;
return: ERROR- duplicate column name "name".
Ditch the * in the SELECT list.
Specify the list of expressions to be returned. And qualify all column references with either the table name, or preferably, a shorter table alias.
And assign an alias to the expression and that will be the name of the column in the resultset.
Also, the query shown is not equivalent to a FULL OUTER JOIN.
If the goal is return all rows from t1, and to also return rows from t2 where a matching row doesn't exist in t1, I'd do something like this...
SELECT t.id AS t_id
, t.name AS t_name
, t.addr AS t_addr
FROM t1 t
UNION ALL
SELECT s.id
, s.name
, s.addr
FROM t2 s
LEFT
JOIN t1 r
ON r.id = s.id
WHERE r.id IS NULL
Try fully qualifying it like
SELECT t1.id, t1.name, t1.address FROM t1

sql to extract same columns from 3 different tables

Hi i have 3 tables i want to extract same columns from 3 tables is this better way to write Select query.
select * from
(
select col1,
select id1 from testid1 where name=pnrtable1.name,
col3 from table1
union all
select coltab1,
select newid2 from testid2 where name=pnrtable2.name,
coltab3 from table2
union all
select namecol1,
select id3 from testid3 where name=pnrtable3.name,
namecol3 from table3
)
Not sure but I think you are after something like this....
select * from
(
select t1.col1, t2.id1 , t1.col3 from table1 t1
INNER JOIN testid1 t2 ON t1.name = t2.name
union all
select t1.coltab1, t2.newid2, t1.coltab3 from testid2 t1
INNER JOIN table2 t2 ON t1.name=t2.name
union all
select t1.namecol1, t2.id3, t1.namecol3 from testid3 t1
INNER JOIN table3 t2 ON t1.name=t2.name
) A

Condition based select and join queries

Query 1:
SELECT if(COUNT(0),1,0) as 'IsPresent'
FROM table1
WHERE Id=1500;
Query2:
If IsPresent is 1, then
select t2.mark,t2.age from table2 t2,table1 t1
where t1.ID=t2.ID order by t1.ID;
If IsPresent is 0, then
select mark,age from table2;
ie. if entry is present in a table, i need to join else i don't need to join.
Is there any way we can achieve this with a single mysql select query?
I think you can union the two different query cases which would look like:
SELECT T2.MARK, T2.AGE
FROM TABLE1 T1, TABLE2 T2
WHERE
T1.ID=T2.ID AND
T1.ID=1500
UNION
SELECT MARK, AGE
FROM TABLE1
WHERE
NOT ID=1500
SELECT t2.mark, t2.age
FROM table2 t2
JOIN table1 t1
ON t1.id = t2.id
WHERE EXISTS
( SELECT *
FROM table1
WHERE id=1500
)
UNION ALL
SELECT t2.mark, t2.age
FROM table2 t2
WHERE NOT EXISTS
( SELECT *
FROM table1
WHERE id=1500
)
which can be simplified to:
SELECT t2.mark, t2.age
FROM table2 t2
LEFT JOIN table1 t1
ON t1.id = t2.id
AND EXISTS
( SELECT *
FROM table1
WHERE id=1500
)