SQL - Sharing fields between derived tables - sql

Is it possible to access fields across derived tables?
SELECT *
FROM (SELECT ID, COL1A FROM Table1) T1
JOIN (SELECT ID, COL2A FROM Table2) T2
ON T1.ID = T2.ID
JOIN (SELECT ID, (COL3A + T2.COL2A) AS SUM FROM Table3) T3
ON T1.ID = T3.ID

You would put the expressions using multiple columns in the SELECT clause:
SELECT t1.ID, t1.COL1A, t2.COL2A, (t3.COL3A + t2.COL2A) as sum
FROM Table1 T1 JOIN
Table2 T2
ON T1.ID = T2.ID JOIN
Table3 T3
ON T1.ID = T3.ID;
There is no need for derived tables at all.

Related

How do I look for non-matching values across 3 SQL tables?

I'm looking to do what I believe is a double-nested check across three tables, but have no idea how to do so.
I have Table1, Table2, and Table3.
All are tied by an ID and a "Longform" and "Shortform" in Table1:
I'm trying to find:
Entries whose IDs appear in Table2 that have the same Longform as those in Table3, but don't share the same Shortform.
This is about as far as I've gotten:
SELECT T2.Longform,T2.Shortform FROM(
SELECT Table1.Longform,Table1.Shortform,Table1.ID FROM OuterTable1.Table1
LEFT JOIN OuterTable2.Table2 on Table1.ID = Table2.ID)
WHERE Table2.ID IS NOT NULL) T2
;
I know I'm probably going to have to do another nested select, or a join, on Outertable3.Table3 but I'm not sure which... Or where...
Any help appreciated as always.
Try the following:
Select *
(
Select T1.*
from T2
inner join T1
on T1.ID = T2.ID
) as Tab
inner join
(
Select T1.*
from T3
inner join T1
on T1.ID = T3.ID
) as Tab2
on Tab.id = Tab2.id
and Tab.Longform = Tab2.Longform
and Tab.Shortform <> Tab2.Shortform
To get the longform join table1 to table2 or table3. Then use EXISTS to check in a subquery if the IDs of table1 are different but the longform is equal.
SELECT *
FROM table2 t21
INNER JOIN table1 t11
ON t11.id = t21.id
WHERE EXISTS (SELECT *
FROM table3 t32
INNER JOIN table1 t12
ON t12.id = t32.id
WHERE t12.id <> t11.id
AND t12.longform = t11.longform);
Assuming ID is unique in all three tables
Select t2.id,t2.shortform, t1.shortform AS shortformTab1, t2.longform
FROM table2 t2
JOIN table3 t3
ON t2.id = t3.id AND t2.longform = t3.longform
JOIN table1 t1
ON t2.id = t1.id AND t2.shortform != t1.shortform

select a columns not exist in another tables multiple columns in sql

I have two tables Tables1 with ID, name, and Table2 has ID1, ID2, and ID3, name1, name2, and name3.
I want to select table1.ID not exists in tables2: ID1, ID2, and ID3
select T1.ID,t1.name
from table1 t1
where not exists (
SELECT *
FROM table2 t2
where t1.ID=t2.ID1 or t1.ID=t2.ID2 or or t1.ID=t2.ID3 )
I get error message for this query
After a little research, I could find this. Basically, you can't have multiple columns for a subquery in a IN or a NOT IN condition in the WHERE clause. This is why your query is currently failing : Your subquery get all the columns from Table2.
From my understanding of your question, you want a select where the results would be the elements that are not existing in Table2.
To do this, you can simply use a LEFT OUTER JOIN. In SQL, I would left join on all three columns, but it seems like Hive does not support multiple conditions in JOIN statements, so you can use the following alternative :
SELECT T1.ID, T1.name
FROM Table1 T1
LEFT JOIN Table2 T2_1 ON T2_1.ID1 = T1.ID
LEFT JOIN Table2 T2_2 ON T2_2.ID2 = T1.ID
WHERE (T2_1.id IS NULL) AND -- the id of Table2 - T2_1
(T2_2.id IS NULL) -- the id of Table2 - T2_2
Just add as many LEFT JOIN and conditions in the WHERE clause as you have columns to check.
Here's a fiddle with this query concept (the data are not the same, but the concept is).
Join first by ID1, then resulted dataset join by ID2, then resulted dataset join by ID3:
select p2.ID, p2.name --pass3
from
(select p1.ID, p1.name --pass2
from
(SELECT T1.ID, T1.name --pass1
FROM Table1 T1
LEFT JOIN Table2 T2 ON T2.ID1 = T1.ID
where T2.ID1 is null --not in ID1
) p1 LEFT JOIN Table2 T2 ON T2.ID2 = p1.ID
where T2.ID1 is null --also not in ID2
) p2 LEFT JOIN Table2 T2 ON T2.ID3 = p2.ID
where T2.ID1 is null --also not in ID3
Joins on 2 and 3 steps will receive already reduced dataset from T1 and this solution may be good for big tables.
SELECT DISTINCT ID,NAME
FROM
(SELECT T1.ID, T1.name
FROM Table1 T1
LEFT OUTER JOIN Table2 T2 ON T2.ID1 = T1.ID
where T2.ID1 is null
union
SELECT T1.ID, T1.name
FROM Table1 T1
LEFT OUTER JOIN Table2 T2 ON T2.ID2 = T1.ID
where T2.ID2 is null
union
SELECT T1.ID, T1.name
FROM Table1 T1
LEFT OUTER JOIN Table2 T2 ON T2.ID3 = T1.ID
where T2.ID3 is null)JO

Convert to join query

select t.* from table1 t where t.id NOT IN(
select Id from t2 where usrId in
(select usrId from t3 where sId=value));
I the result i need is like if there are matching id's in t1 and t2 then those id's should be omitted and only the remaining rows should be given to me. I tried converting into join but it is giving me the result i wanted. Below is my join query.
SELECT t.* FROM table1 t JOIN table2 t2 ON t.Id <> t2.Id
JOIN table3 t3 ON t3.Id=t2.Id WHERE t3.sId= :value
This doesn't feth me the correct result. it was returning all the rows, but i want to restrict the result based on the matching id's in table t1 and table t2. Matching id's should be ommited from the result.I will be passing the value for sId.
I believe this to be an accurate refactor of your query using joins. I don't know if we can do away with the subquery, but in any case the logic appears to be the same.
select t1.*
from table1 t1
left join
(
select t2.Id
from table2 t2
inner join table3 t3
on t2.usrId = t3.usrId
where t3.sId = <value>
) t2
on t1.Id = t2.Id
where t2.Id is null
Let's break down and solve problem step by step.
So your query
select t.* from table1 t where t.id NOT IN(
select Id from t2 where usrId in
(select usrId from t3 where sId=value));
on converting the inner query to JOIN will yield
select t.* from table1 t where t.id NOT IN
(SELECT T2.ID FROM T2 JOIN T3 on T2.UsrID =T3.UsrID and T3.sID=value)
which on further converting to JOIN with outer table will be
select t.* from table1 t LEFT JOIN
(SELECT T2.ID FROM T2 JOIN T3 on T2.UsrID =T3.UsrID and T3.sID=value)t4
ON t.id =T4.ID
WHERE t4.ID is NULL
In case you completely want to remove sub-query you can try like this
SELECT t.*
FROM table1 t
LEFT JOIN T2
ON T.ID=T2.ID
LEFT JOIN T3
ON T3.UsrId=T2.UsrID AND T3.sId=value
WHERE T3.UsrID IS NULL

SQL: select from t1 all rows for which there's no corresponding in t2

Let's say I have a table t1 with only one column: id, and I have a table t2 with two columns: id and Memo. I need to select those id from t1, for which there is NO row in t2 that satisfies both of the following two conditions t1.id = t2.id and t2.Memo = 'myText'. How can I do that? I have tried using join, but that selects row that do satisfy some conditions, whereas I need the opposite.
SELECT *
FROM t1
WHERE NOT EXISTS (SELECT 1
FROM t2
WHERE t2.id = t1.id
AND t2.Memo = 'myText')
One way to do it is using LEFT JOIN:
select id
from t1
left join t2
on t1.id = t2.id and t2.Memo = 'myText'
where t2.id is null
I'm not good in understanding your question:
You mean those t1.id EXISTS in t2 BUT the corresponding t2.Memo <> 'myText'?
SELECT t1.id FROM t1 JOIN t2
ON t1.id = t2.id
HAVING t1.id NOT IN (SELECT id FROM t2 WHERE Memo = 'myText');
Or all t1.id either NOT EXISTS in t2 or EXISTS but Memo <> 'myText'?
SELECT id FROM t1 WHERE id NOT IN (SELECT id FROM t2 WHERE Memo = 'myText');

SQL: Calculating the Max date across multiple tables

I am trying to find the max date across multiple columns (in multiple tables). I have an SQL query that I think is almost workable, but am having a hard time debugging it. The problem is that it never returns anything. Any ideas on what I'm doing incorrectly? I don't get any errors, just an empty row "maxdate."
Here's my query:
SELECT
(
SELECT MAX(dates) FROM
(
SELECT dates = t1.UpdateDate
UNION ALL
SELECT dates = t2.UpdateDate
UNION ALL
SELECT dates = t3.UpdateDate
UNION ALL
SELECT dates = t4.UpdateDate
) as dateAcrossColumns
) as maxdate
FROM table1 as t1
join table2 as t2 on t1.ID = t2.ID
join table3 as t3 on t1.ID = t3.ID
join table4 as t4 on t1.ID = t4.ID
join table5 as t5 on t1.Status = t5.Status
WHERE t1.id = #param and t5.status <> 3
First join you join to table 2 using table 1's ID and table 3's ID. I presume you mean table 1's ID and table 2's ID?
join table2 as t2 on t1.ID = t3.ID
Should be:
join table2 as t2 on t1.ID = t2.ID
Now that this has been changed;
I tried your query and it works fine, are you sure that your joins are bringing back any rows? To test it replace your SELECT statement with SELECT *, if you get no rows back then they are being filtered out somewhere in your joins / WHERE.
If it's possible for any of the tables to not have any rows for the given #param, the (inner) joins will filter out all of the other tables.
Try unioning the dates and get the max of the unions
WITH allDates AS (
SELECT UpdateDate
FROM Table1
WHERE ID = #param
UNION
SELECT UpdateDate
FROM Table2
WHERE ID = #param
UNION
SELECT UpdateDate
FROM Table3
WHERE ID = #param
UNION
SELECT UpdateDate
FROM Table4
WHERE ID = #param
UNION
SELECT t5.UpdateDate
FROM Table5 AS t5
JOIN Table1 AS t1
ON t5.Status = t1.Status
WHERE t1.ID = #param
)
SELECT MAX( UpdateDate ) AS MaxDate
FROM allDates
Cant think of a simpler way of doing this :)
SELECT MAX(Dates) AS RequiredDate
FROM (
SELECT t1.UpdateDate AS DateOne
,t2.UpdateDate AS DateTwo
,t3.UpdateDate AS DateThree
,t4.UpdateDate AS DateFour
FROM table1 as t1
join table2 as t2 on t1.ID = t2.ID
join table3 as t3 on t1.ID = t3.ID
join table4 as t4 on t1.ID = t4.ID
join table5 as t5 on t1.[Status] = t5.[Status]
WHERE t1.id = #param and t5.[Status] <> 3
)t
UNPIVOT (Dates FOR DateCols
IN (DateOne, DateTwo,DateThree,DateFour))up
I was trying to solve a similar problem to find the last modified date across a set of joined tables in MySQL. The following worked for me using a combination of GREATEST and MAX:
SELECT GREATEST(MAX(t1.modified), MAX(t2.modified), MAX(t3.modified),
MAX(t4.modified)) AS lastmodified
FROM `table1` AS t1
LEFT JOIN `table2` AS t2 ON t1.id = t2.t1_id
LEFT JOIN `table3` AS t3 ON t2.id = t3.t2_id
LEFT JOIN `table4` AS t4 ON t3.id = t4.t3_id
WHERE t1.id = #param