Sql : left join exclude values based on another table - sql

I am trying to figure out this without any success i have tried going through several posts but cannot come to a solution. Situation is like this : ( There are no foreign key constraints )
Table A ID | VAL Table B ID|VAL|TEMP RESULT REQUIRED
1 | A 1| A | 2 A
1 | B 1| A | 2 C
1 | C 1| B | 1 D
1 | D 1| C | 2 E
1 | E 1| D | 2 F
1 | F 1| G | 6 H
1 | H
When i run SELECT DISTINCT A.VAL,B.TEMP FROM A
LEFT JOIN B
ON A.VAL=B.VAL AND B.TEMP > 1
This is returning all rows of TABLE A and rows which are common to TABLE B but not validating the condition ( b.val > 1) because since row B is in Table A, it is getting included in the result . However i want that if val b < 2 then it should be not included in result.

I think this is what you are looking for:
select distinct a.val
from a
left outer join b on (a.val = b.val)
where
(b.temp > 1 or b.val is null)
You want to do the test on B.TEMP after doing the outer join. In the where clause, you are testing for two things. Firstly, you a checking that the value of TEMP is greater than 1. This is the condition set forward in the question. The second condition (b.val is null) covers those rows from table A that don't have a corresponding row in table B. For example, rows 'E', 'F' and 'G' in table A don't match to anything in table B, so all the columns of B will be null after the outer join. you might want to look at this link for more information on outer joins: What is the difference between "INNER JOIN" and "OUTER JOIN"?
Howveer, I have noticed that the rows in table B don't need to be unique. You have two rows where VAL= 'A'. What would happen if the TEMP column had different values where one met the condition and the other didn't.
Another option for getting the result might just be to use NOT IN or NOT EXISTS. An example might be:
select * from a
where a.val not in (
select val
from b
where temp < 2
);

If you want to exclude results from the second table, then don't use a left outer join. Just use an inner join:
SELECT DISTINCT A.VAL, B.TEMP
FROM A INNER JOIN
B
ON A.VAL = B.VAL AND B.TEMP > 1;
Or, in your case, you might want B.TEMP < 2.

Add following WHERE clause to your query
WHERE B.Val IS NOT NULL

Related

How can I get full results in SQL query using 3 tables, where 1 of them keeps relation of 2 another?

I need help writing a query to display results I want.
"Table 3 - relations" keeps all relations between table 1 and 2.Often, relation between table 1 and 2 will not exist in table 3 so I want to see missing relation in the results for all Table 1 rows - see expected Results below.
I can't modify these tables - I have only SELECT privilege.
Data and expected result below:
Table 1 - a:
a_id, a_name
e.g.:
1 A
2 B
Table 2 - b:
b_id, b_name
e.g.:
1 X
2 Y
Table 3 - relation:
asset1_id (it's always id from Table 1), asset2_id (it's always id from Table 2), relation_type
e.g.:
1 1 covers
1 2 covers
Expected result:
Table1_name, Table2_name, Table3_relation_type (including NULL for b_name and relation_type when such relation does not exist in Table 3 - relation)
e.g.
A X covers
A Y covers
B NULL NULL
I can't get the 3rd expected line with NULLs.
I think that this query will produce those results.
select a.name as a_name,b.name as b_name, r.relation_type from relation r
join a on a.id=r.asset1_id
join b on b.id=r.asset2_id
union
select a.name as a_name,b.name as b_name,r.relation_type from relation r
full outer join a on a.id=r.asset1_id
full outer join b on b.id=r.asset2_id
where a.id is null or b.id is null
With your data sample you could try this one.
It should work both hive or impala.
SELECT t1.name ,t2.name ,r.relation_type
FROM relation r
FULL OUTER JOIN table1 t1 ON(t1.id = r.id1)
FULL OUTER JOIN table2 t2 ON(t2.id = r.id2);
+------+------+---------------+
| name | name | relation_type |
+------+------+---------------+
| A | X | covers |
| A | Y | covers |
| B | NULL | NULL |
+------+------+---------------+
WITH
cte_A AS (
SELECT id as a_id, name as a_name
FROM a
),
cte_C AS (
SELECT c.asset_id1 as a_id, b.name, c.relation
FROM c
LEFT JOIN b ON c.id=b.asset_id2
)
SELECT cte_A.a_name, cte_C.name as c_name, cte_C.relation
FROM cte_A
LEFT JOIN cte_C ON cte_A.a_id=cte_C.a_id

How can I create a view where each row in one table is treated as a child of each row in another table?

I am attempting to create a view which that combines two tables to have the form below.
Table A (column FIRST)
FIRST
-----
A
B
C
Table B (column SECOND)
SECOND
-----
1
2
3
Result
FIRST | SECOND
------|-------
A | 1
A | 2
A | 3
B | 1
B | 2
B | 3
C | 1
C | 2
C | 3
I have been struggling to wrap my brain around this one. Something like the below code is what I would like to end up with for my view, to make it similar to my other views, but all the options I've tried haven't worked quite right.
SELECT
FIRST,
'' AS SECOND
FROM Table A
UNION ALL
SELECT
'' AS FIRST,
SECOND
FROM Table B
You are looking for a cross join:
select a.first, b.second
from a cross join
b
order by a.first, b.second;
You can use a CROSS JOIN. For example:
CREATE VIEW v AS
SELECT a.first, b.second
FROM tablea a
CROSS JOIN tableb b

Inner join table a or b based on existence

I've got these 3 tables:
Table A
---------------------------
|KEY | VALUE_A1 | VALUE_A2|
---------------------------
Table B
------------------------------
|KEY | APPLICATION | VALUE_B1|
------------------------------
Table C
------------------------------
|KEY | APPLICATION | VALUE_C1|
------------------------------
I want to return A.VALUE_A1, A.VALUE_A2 along with B.VALUE_B1 or C.VALUE_C1 based on the existence of the application in B or C. This application is given in de where-clause in de script.
Example:
Table A has 10 records. Table B contains 6 records with application 'APP1'. Table C contains 4 records with application 'APP2'. Both table B and C are through KEY connected to table A. If the application given is 'APP1' then I want to return B.VALUE_B1. If 'APP2' is given I want to return C.VALUE_C1.
Is it possible to INNER JOIN on one of two tables based on a CASE-like condition?
Not INNER JOIN but LEFT JOIN like this
select A.KEY
A.VALUE_A1, A.VALUE_A2,
CASE WHEN B.VALUE_B1 IS NOT NULL THEN B.VALUE_B1 ELSE C.VALUE_C1 END AS RESULT_VALUE
from A
LEFT JOIN B on A.key=B.key
LEFT JOIN C on A.key=C.key
UPDATE: There is an alternative
select A.KEY
A.VALUE_A1, A.VALUE_A2,
sub.VALUE AS RESULT_VALUE
from A
INNER JOIN (SELECT KEY, VALUE_B1 as VALUE
FROM B
UNION ALL
SELECT KEY, VALUE_C1 as VALUE
FROM C) sub on A.KEY=sub.KEY

Oracle SQL Query to retrieve records where a value in a column equals the count of values in another table

I have two tables:
Table A
AId | ImageCount
1 | 1
2 | 1
3 | 2
Table B
BId | AForeignKey
1| 1
2| 3
3| 3
I was able to get this query, which gives me a visual comparison of the values:
SELECT t1.AId, t1.ImageCount, COUNT(t2.AForeignKey) AS RecordsInB
FROM A t1
LEFT JOIN B t2 ON tw.AForeignKey = t1.AId
GROUP BY t1.AId, t1.ImageCount
but I can't figure out how to eliminate those rows where the ImageCount doesn't equal the RecordsInB. All I really care about it the AId column, but I'm displaying the other columns in the above query just so I can visually compare.
So the output should look like this:
AId
1
3
Or for visual comparison:
AId|ImageCount|RecordsInB
1| 1 | 1
3| 2 | 2
I hope that makes sense.
If I understand well, you need to filter the result of your query to only keep the rows having t1.imageCount = COUNT(t2.AForeignKey).
If so, simply add this condition to your query:
SELECT t1.AId, t1.ImageCount, COUNT(t2.AForeignKey) AS RecordsInB
FROM tableA t1
LEFT JOIN tableB t2 ON t2.AForeignKey = t1.AId
GROUP BY t1.AId, t1.ImageCount
having t1.imageCount = COUNT(t2.AForeignKey)

Join 2 Tables and display everything

I have 2 simple tables:
table a:
id | txt
---+----
0 | aaa
1 | bbb
2 | ccc
table b:
id | tel
---+----
0 | 000
2 | 111
I am trying to join 2 tables like this:
SELECT a.*,b.*
FROM a,b
WHERE a.id=b.id
It works, but, if there is no entry in the "b" table it wont show anything.
what the sql shows is something like this:
id | txt | tel
---+-----+----
0 | aaa | 000
2 | ccc | 111
I also want to list the "empty" row a.id=1:
id | txt | tel
---+-----+-----
1 | bbb | NULL
Any ideas? Thanks!
(SQL is for MS Access / oledb)
You want a left outer join (or a full outer join, if you want rows in which there is no entry in the a table also).
SELECT a.*,b.* FROM a LEFT OUTER JOIN b ON a.id=b.id
Depending the system, the syntax LEFT JOIN may work as well.
In MSAccess query designer, right click on the relationship connection between the two tables, and edit its properties. Modify it to 'show all records from table a'.
This:
SELECT a.*,b.*
FROM a, b
WHERE a.id = b.id
...is ANSI-89 inner join syntax, and I highly recommend using ANSI-92 syntax instead:
SELECT a.*,
b.*
FROM TABLE_A a
JOIN TABLE_B b ON b.id = a.id
...mostly because ANSI-88 syntax for left joining to tables wasn't consistently implemented on various databases. This will return the results you expect:
SELECT a.id,
a.txt,
b.tel
FROM TABLE_A a
LEFT JOIN TABLE_B b ON b.id = a.id
A LEFT JOIN means you'll get all the records from TABLE_A in this example, and when there is a matching record (based on the ON criteria) in TABLE_B, the value will be displayed. Otherwise, the TABLE_B column references will return NULL values.
For more information on JOINs, see this page for a great pictorial demonstration of what each one represents and how they compare.