SQL - Finding optional value in another table - sql

In the scenario where there are two tables, one column in the first has a nullable key to another table.
table1_id | table1_key | table2_id | table2_value
----------+------------+-----------+--------------
1 | 1 | 1 | 3
2 | | |
3 | 3 | 3 | 1
4 | 1 | 1 | 3
With a single efficient statement, I want to get all rows from table1 and data from table2 if they exist.
My current method does a union between two statements.
SELECT
table1.id as table1_id,
table1.fkey as table1_key,
table2.id as table2_id,
table2.value as table_value
FROM
table1,
table2
WHERE
table1.fkey = table2.id
UNION
SELECT
table1.id as table1_id,
null,
null,
null
FROM
table1,
table2
WHERE
table1.fkey = NOT IN (SELECT id FROM table2)
How can this be done more efficiently in a single select statement?

A left join would do the job,
SELECT
table1.id as table1_id,
table1.fkey as table1_key,
table2.id as table2_id,
table2.value as table_value
FROM table1
LEFT OUTER JOIN table2
ON table1.fkey = table2.id

You need a join between table1 and table2 on the foreign key relationship.
From your question, I understand that column fkey in table1 is a foreign key to column id in table2.
You want to retrieve rows from table1 even if there is no matching row in table2. Hence you need a left outer join
select t1.id as t1_id
,t1.fkey as t2_id
,t2.value as t2_value
from table1 t1
left outer join table2 t2
on t1.fkey = t2.id

Related

How to select from joined table with WHERE clause only when value exist?

I want to SELECT one record from table1 (WHERE t1.id = 1) and then JOIN table2 and table3 (t2.field2 and t3.field3) to table1 but ONLY if the values exists (IS NOT NULL).
So for example, if the value doesn't exist for t3.field3, the field3 column is not displayed for that table...
t1
id | field1
---------------
1 | f1val
2 | f1val
3 | f1val
t2
id(fk) | field2
-------------------
1 | f2val
2 | null
3 | null
t3
id(fk) | field3
-------------------
1 | null
2 | f3val
3 | f3val
the code I tried to do is this:
SELECT t1.id, t2.field1, t3.field3
FROM (
SELECT t1.id
FROM t1
WHERE t1.id = 1
)
LEFT JOIN t2 ON t2.id = t1.id AND t2.id is not null
LEFT JOIN t3 ON t2.id = t1.id AND t3.id is not null;
The joined table returned from the query above looks like this:
id | field2 | field3
----------------------------
1 | f1val | null
However, since field3 is null, I want it to return only the id and field2 like this:
id | field2
----------------
1 | f1val
Your help will be highly appreciated.
You could return one column, using coalesce():
SELECT t1.id, COALESCE(t2.field1, t3.field3) as field_2_3
FROM t1 LEFT JOIN
t2
ON t2.id = t1.id LEFT JOIN
t3
ON t3.id = t1.id
WHERE t1.id = 1;
However, you cannot sometimes return two columns and sometimes return 3 columns.
Notes:
The subquery on t1 is utterly unnecessary. You can just apply the filter in a single WHERE clause.
The comparisons for IS NOT NULL are unnecessary because they fail the JOIN condition anyway.
The last JOIN condition is presumably on t3.id = t1.id.

Find values where related must have list of values

I'm trying to find a simple solution for my SQL Server problem.
I have two tables look like this:
table1
--id
-- data
table2
--id
--table1_id
--value
I have some records like this:
Table1
+-----------------------+
| id | data |
+-----------------------+
| 1 | ? |
+-----------------------+
| 2 | ? |
+-----------------------+
Table2
+-----------------------+
|id | table1_id | value |
+-----------------------+
| 1 | 1 | 'a' |
+-----------------------+
| 2 | 1 | 'b' |
+-----------------------+
| 3 | 2 | 'a' |
+-----------------------+
Now I want to get table1 with all it's additional values where the relation to table2 has 'a' AND 'b' as values.
So I would get the id 1 of table1.
Currently I have an query like this:
SELECT t1.[id], t1.[data]
FROM [table1] t1,
(SELECT [id]
FROM [table1] t1
JOIN [table2] t2 ON t1.[id] = t2.[table1_id] AND t2.[Value] IN('a', 'b')
GROUP BY t1[id]
HAVING COUNT(t2.[Value]) = 2) x
WHERE t1.id = x.id
Has anyone an idea on how to achieve my goal in a simpler way?
One way uses exists:
select t1.*
from table1 t1
where exists (select 1
from table2 t2
where t2.table1_id = t1.id and t2.value = 'a'
) and
exists (select 1
from table2 t2
where t2.table1_id = t1.id and t2.value = 'b'
);
This can take advantage of an index on table2(table1_id, value).
You could also write:
select t1.*
from table1 t1
where (select count(distinct t2.value)
from table2 t2
where t2.table1_id = t1.id and t2.value in ('a', 'b')
) = 2 ;
This would probably also have very good performance with the index, if table2 doesn't have duplicates.
SELECT T1.[id], T1.[data]
FROM table1 AS T1
JOIN table2 AS T2
ON T1.[id]=T2.[table1_id]
JOIN table2 AS T3
ON T1.[id]=T3.[table1_id]
WHERE
T2.[Value] ='a'
AND T3.[Value] = 'b'
As Gordon Linoff suggested, exists clause usage works as well and could be performance efficient depending on the data you are playing with.
you have to do several steps to solve the problem:
established which records are related to table 1 and table 2 and which of these are of value (A or B) and eliminate the repeated ones with the group by(InfoRelationate )
validate that only those related to a and b were allowed by means of a count in the table above (ValidateAYB)
see what data meets the condition of table1 and table 2 and joined table 1
this query meets the conditions
with InfoRelationate as
(
select Table2.table1_id,value
from Table2 inner join
Table1 on Table2.table1_id=Table1.id and Table2.value IN('a', 'b')
group by Table2.table1_id,value
),
ValidateAYB as
(
select InfoRelationate.table1_id
from InfoRelationate
group by InfoRelationate.table1_id
having count (1)=2
)
select InfoRelationate.table1_id,InfoRelationate.value
from InfoRelationate
inner join ValidateAYB on InfoRelationate.table1_id=ValidateAYB.table1_id
union all
select id,data
from Table1
Example code

SQL Query subquery in select

I have 2 tables.
Table1
+----+------+
| Id | Name |
+----+------+
| | |
+----+------+
Table2
+-----+-----------+------+-------+---------+
| Id | Table1_ID | Name | Value | Created |
+-----+-----------+------+-------+---------+
| | | | | |
+-----+-----------+------+-------+---------+
When I run a SELECT * FROM Table2, I want the Table1_ID to be replaced with the name of that item ID from Table 1, rather than the ID. How can I do that?
User Inner join, Like this
SELECT
T2.Id
T1_Name = T1.Name ,--Table1_ID
T2_Name = T2.Name
T2.Value
T2.Created
FROM Table1 T1
INNER JOIN Table2 T2
ON T1.ID = T2.Table1_ID
You can use INNER JOIN for that.
INNER JOIN Syntax 1
SELECT *
FROM table1
INNER JOIN table2 ON table1.id = table2.fk_id
INNER JOIN Syntax 2
SELECT *
FROM table1
INNER JOIN table2
WHERE table1.id = table2.fk_id
  
SELECT Table2.Id, Table2.Name, Table1.Name, Table2.Value, Table2.Created
FROM Table2
INNER JOIN Table1 ON Table1.ID = Table2.Table1_ID
Recommended Readings
http://sql.sh/cours/jointures/inner-join
https://www.w3schools.com/sql/sql_join_inner
https://www.tutorialspoint.com/sql/sql-inner-joins

ODBC Excel driver SQL mapping multiple foreign ids to the same table

I have a table where 4 columns contains ID values from a second table that represents a pair (ID,TERM). For instance:
Table1:
KEYID | ID1 | ID2 | ID3 | ID4
Table2:
ID | TERM
Is there any way to create an SQL query that provides for instance a table like:
KEYID | TERM_ID1 | TERM_ID2 | TERM_ID3 | TERM_ID4
where TERM_ID1, TERM_ID2, TERM_ID3 and TERM_ID4 are the corresponding values of the TERM column in Table2?
You could so something simple like this. It joins to table2 once for each corresponding value and uses the Term in the final select;
SELECT
t1.KeyID
,t2.Term Term_ID1
,t3.Term Term_ID2
,t4.Term Term_ID3
,t5.Term Term_ID4
FROM Table1 t1
JOIN Table2 t2 ON t1.ID1 = t2.ID
JOIN Table2 t3 ON t1.ID2 = t3.ID
JOIN Table2 t4 ON t1.ID3 = t4.ID
JOIN Table2 t5 ON t1.ID4 = t5.ID

Update multiple rows using select statements

Let's say I have these tables and values:
Table1
------------------------
ID | Value
------------------------
2 | asdf
4 | fdsa
5 | aaaa
Table2
------------------------
ID | Value
------------------------
2 | bbbb
4 | bbbb
5 | bbbb
I want to update all the values in Table2 using the values in Table1 with their respective ID's.
I know I can run this:
UPDATE Table2
SET Value = t1.Value
FROM Table2 t2
INNER JOIN Table1 t1 on t1.ID = t2.ID
But what can I do if Table1 and Table2 are actually select statements with criteria? How can I modify the SQL statement to take that into consideration?
This is how such update queries are generally done in Oracle. Oracle doesn't have an UPDATE FROM option:
UPDATE table2 t2
SET t2.value = ( SELECT t1.value FROM table1 t1
WHERE t1.ID = t2.ID )
WHERE EXISTS ( SELECT 1 FROM table1 t1
WHERE t1.ID = t2.ID );
The WHERE EXISTS clause will make sure that only the rows with a corresponding row in table1 are updated (otherwise every row in table2 will be updated; those without corresponding rows in table1 will be updated to NULL).