Use SELECT subquery within UNION - sql

I have two tables:
Table 1
Table 2
I am trying to write a query to SELECT all records for both tables, using UNION (columns ID, Date and Amount). The tables are linked by ID. When selecting the records in Table 2 however during the UNION, if the related ID in Table 1 has a True or False value of TRUE, I want to change the Date of the Table 2 record to the date in Table 1, ultimate acheiving this:
Is this possible?

The 2nd query of UNION ALL should be a join of the tables:
select id, date, amount
from Table1
union all
select
t2.id,
case when t1.trueorfalse = 'TRUE' then t1.date else t2.date end
t2.amount
from Table2 t2 inner join Table1 t1
on t1.id = t2.id
The CASE expression will return either the date from Table1 or from Table2.
If your database supports the Boolean data type maybe you should use TRUE instead of 'TRUE'.

This seems like a convenient place to use a lateral join, if your database supports it:
select v.*
from table1 t1 join
table2 t2
on t1.id = t2.id cross join lateral
(values (t1.id, (case when t1.true_or_false = 'true' then t2.date else t1.date end), t1.amount),
(t2.id, t2.date, t2.amount)
) v(id, date, amount);

Related

Join 2 tables in SQL and create a flag column based on a match

I am new to SQL. I have 2 tables]
Table 1:
id product location
1 banana costco
2 apple walmart
3 lemons target
Table 2:
id
1
2
4
I want to join these 2 tables based on id. If there is a match, I want to create a new column in resultant table so that my result looks like this
id flag
1 true
2 true
3 false
4 true
i.e if the id exists in table2, I want to flag as true else false. I want to include all ids in the resultant table
How can I do this in SQL (Running in Athena)?
I can join through following but I don't know to create a column based on a match
SELECT t2.id from table2 t2,
LEFT JOIN table1 t1 ON t1.id=t2.id
What you are looking for is a full outer join, but MySQL is one of the very few RDBMS that don't support full outer joins.
A full outer join would look like this:
SELECT
COALESCE(t1.id, t2.id) AS id,
(t1.id IS NOT NULL AND t2.id IS NOT NULL) AS flag
FROM table1 t1
FULL OUTER JOIN table2 t2 ON t2.id = t1.id
ORDER BY COALESCE(t1.id, t2.id);
Here are two alternative approaches:
Collect all IDs, then check whether they exist in both tables:
SELECT
id
id IN (SELECT id FROM table1)
AND
id IN (SELECT id FROM table2) AS flag
FROM
(
SELECT id FROM table1
UNION
SELECT id FROM table2
) ids
ORDER BY id;
SELECT the matches, the missing table2 IDs, and the missing table1 IDs, then union these results.
SELECT id, true AS flag FROM table1 JOIN table2 USING (id)
UNION ALL
SELECT id, false AS flag FROM table1 WHERE id NOT IN (SELECT id FROM table2)
UNION ALL
SELECT id, false AS flag FROM table2 WHERE id NOT IN (SELECT id FROM table1)
ORDER BY id;
UPDATE: I just see that you tagged both MySQL and Amazon Athena. These are two different DBMS. MySQL does not support full outer joins, Athena does. So, for Athena all three queries should work, while for MySQL ony the second and third will.
Try with a UNION:
SELECT
id,
true AS flag
FROM
table2
UNION
SELECT
id,
false AS flag
FROM
table1
WHERE
id NOT IN (
SELECT id FROM table2
)
SELECT
id,
CASE
WHEN id in (SELECT id FROM table2) THEN 'true'
ELSE 'false'
END AS 'flag'
FROM table1
UNION
SELECT
id,
CASE
WHEN EXISTS (SELECT 1 FROM table2) THEN 'true'
ELSE 'false'
END AS 'flag'
FROM table2;
Select
(case when table1.id is null then table2.id else table1.id end) as id,
(case when table2.id is null then false else true end) as flag
from table1 full join table2
on table1.id = table2.id
full join will help get you all ids, in selection you can use case statement to avoid picking nulls in id and flag columns.
You can do it as follows :
select t2.id, 'true' as flag
from table2 t2
union
select id, 'false' as flag
from table1
where id not in ( select id from table2)
Since all ids in table2 must be true, and the others that are not in table2 must be false there is no need of join.
you can try it from here : https://dbfiddle.uk/QIPoFRTb
This is to have them ordered :
select *
from (
select t2.id, 'true' as flag
from table2 t2
union
select id, 'false' as flag
from table1
where id not in ( select id from table2)
) as s
order by id;

Optimize SQL Query, need suggestions

I have a table in SQL Server having 4 columns:
Invoice No, Date, Amt and ID
I have to find invoices that have same Invoice No, date and Amt but different ID.
I'm populating the results doing self join but seems like it's not the optimized way to fetch results.
My query:
select * from table t1 join
table t2 on t1.invoice = t2.invoice
where t1.invoice=t2.invoice and t1.amount=t2.amount and t1.date =t2.date and t1.id!=t2.id
Kindly suggest me an optimized way to fetch the correct result.
try this. using left join and filter those nulls.
select * from (
select t1.invoiceno, t1.date, t1.amt, t1.id, t2.id as t2ID
from invoices t1
left join invoices t2 on t2.invoiceno = t1.invoiceno
and t2.date = t1.date
and t2.amt = t1.amt
and t2.id != t1.id) t3
where coalesce(t3.t2ID, 0) != 0
You might use indexes to speed up the retrieving from large databases.
Use sub query but don't use a sub query just to show one column.
I advised to use sub query as new table to use joins.
just like the first answer.
use not exists
select t1.* from table t1
where not exists( select 1 form
table t2 where t1.invoice = t2.invoice
and t1.invoice=t2.invoice and t1.amount=t2.amount
and t1.date =t2.date and t1.id=t2.id
having count(*)>1
)
have to find invoices that have same Invoice No, date and Amt but different ID.
Use exists:
select t.*
from t
where exists (select 1
from t t2
where t2.Invoice = t.invoice and
t2.Date = t.date and
t2.amount = t.amount and
t2.id <> t.id
)
order by t.invoiceNo, t.date, t.amount, t.id;
This will show the matching invoices on adjacent rows. For performance, you want an index on (invoice, date, amount, id).
If you just want triplets where this occurs, you can use aggregation:
select invoice, date, amount, min(id), max(id)
from t
group by invoice, date, amount
having count(distinct id) > 1;
Note: If there are more than two duplicates, this only shows two ids.

SQL Server - Return all records from LEFT table and only non matching records from right table

I have 2 tables with the same structure (field names). Table1 and Table2.
I need to return all records from Table1 and only records from Table2 that do not match/join to a record in Table1.
Table2 has more records than Table1.
I am joining the 2 tables on 3 fields.
So basically I want all records from table1 returned and only records that don't have a match (joining on the 3 fields) to table1 from table2 returned.
Put another way, Table1 records take precedence over table2 records in my final result output when the records exist in both tables (same value for the 3 fields)
I started writing something like the below but I don't think it will work. Should I use a left outer join instead?
Select * from table1 t1
left join table2 t2 on t1.id = t2.id and t1.date = t2.date and t1.custid= t2.custid
where t2.id is null or t2.date is null or t2.custid is null
So, you need every row from table1 plus the rows from table2 that don't match with table1?:
SELECT *
FROM table1
UNION ALL
SELECT *
FROM table2 t2
WHERE NOT EXISTS(SELECT * FROM table1
WHERE id = t2.id
AND date = t2.date
AND custid = t2.custid);
Select * from table1 t1
Union
Select * from table2 t2
Where Not exists
(Select * from table1
Where id = t1.id
and date = t1.date
and custid= t1.custid)

Select from table not in another table

I have two tables, each with the following fields: IDnumber, SectionNumber, Date. There is overlapping information in the two tables.
How do I select only rows that do NOT overlap (ie. in one table but not the other)?
You can use a NOT IN in your WHERE clause.
SELECT IDnumber, SectionNumber, Date
FROM table1
WHERE IDnumber NOT IN (SELECT IDnumber FROM table2)
OR NOT EXISTS
SELECT IDnumber, SectionNumber, Date
FROM table1 t1
WHERE NOT EXISTS (SELECT IDnumber FROM table2 t2 WHERE t1.IDnumber = t2.IDnumber)
Which DBMS?
If SQL Server, then it's almost what you wrote in the title...
SELECT *
FROM Table1
WHERE IDnumber NOT IN (SELECT IDnumber FROM Table2)
If you want to compare multiple columns, you need an outer join:
select table1.*
from table1 left outer join
table2
on table1.id = table2.id and
table1.SectionNumber = table2.SectionNumber and
table1.date = table2.date
where table2.id is null
In the case where you might have many matches between the tables, then the join can be inefficient. Assuming you only want those three fields, you can use a trick that avoids the join:
select id, SectionNumber, date
from ((select 0 as IsTable2, id, SectionNumber, date
from table1
) union all
(select 1 as IsTable2, id, SectionNumber, date
from table2
)
) t
group by id, SectionNumber, date
having max(isTable2) = 0
SELECT *
FROM Table1 t1 left join Table2 t2
on t1.id=t2.id
where t2.id is null

Can I use the exists function in the select part of an SQL query?

I need to run a query where one of the fields returned is a yes or no if there is a row in another table matching one of the key fields in the first table.
Sounds like a job for join, except the second table is one to many and I just need to know if there are zero or a non zero number of rows in the secondary table.
I could do something like this:
select t1.name, t1.id, (select count(1) from t2 where t1.id=t2.id) from t1
but I'd like to avoid making an aggregate subquery if possible.
It was mentioned to me that I could use the exists() function, but I'm not seeing how to do that in a select field.
This is sybase 15 by the way.
You could still do the JOIN, something like this:
SELECT t1.name, t1.id, CASE WHEN t2.id IS NULL THEN 0 ELSE 1 END Existst2
FROM t1
LEFT JOIN (SELECT id FROM t2 GROUP BY id) t2
ON t1.id = t2.id
ahhh, I got it from another stackoverflow quetion...
case when exists (select * from t2 where t1.id = t2.id) then 1 else 0 end
I am just writing down the syntax here:
if exists (select * from table1 t1 inner join table1 t2 on t1.id = t2.id )
select * from table2
How about this query ( Work with all databases )
select t1.name, t1.id, 'Y' as HasChild
from t1
where exists ( select 1 from t2 where t2.id = t1.id)
UNION
select t1.name, t1.id, 'N' as HasChild
from t1
where NOT exists ( select 1 from t2 where t2.id = t1.id)