Count rows from left table without corresponding value in the right table - sql

I want to count rows from left table (of a 1-to-many relation between two tables) that do not have PK-FK representative in right table
Left table
id | value
-----------
1 | a
2 | b
3 | c
Right table
id | id-left | value
--------------------
.. | 1 | ....
the expected result is 2 as rows with id 1 and 3 in left table have no counterpart in right table.

You can use a not exists anti-semi-join:
select count(*)
from l
where not exists (
select * from r where r.id_left = l.id
);

Related

I want to join to a table, but include All records if the table being joined to is a certain ID

I want to join to a table, but include All records if the table being joined to is a certain ID.
I have a list of records with a type_id:
RECORD
id | type_id
---|---
1 | 1
2 | 1
3 | 2
TYPE
id | type_desc
---|---
1 | type1
2 | type2
3 | all
USER
id | type_id
---|---
1 | 1
2 | 3
3 | 2
Record to type is one to one, user to type is one to one, and the "Type" on a record has to be 1 or 2. User can be 1, 2 or 3. The way this would go with a normal join is
select * from record r
inner join user u on u.type_id = r.type_id
where u.user_id=:userId
But now I need to factor in that "All" type, and basically just ignore the join/return all results if the user's type is 3.
So if the user being queried is ID 1, only records 1 and 2 (type 1) would be returned. If userId is 3, only record 3 is returned. But if user ID is 2, corrresponding to the "All" type, then 1,2,3 should be returned.
I hope this helps you:
With dtAll as (
select * from user u
where u.type_id = 3
limit 1
)
select * from record r
inner join user u on u.type_id = r.type_id or exists( select * from dtAll )

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

Oracle - Conditional Join eliminating additional joins where unnecessary

Let’s say I have a simplified table structure as follows:
Table A - ID (PK)
Table B - ID (PK), AID = FK to Table A
Table C - ID (PK), BID = FK to Table B
Table D - ID (PK), CID = FK to Table C
Query something like so:
SELECT * FROM TABLE_A TBLA
LEFT JOIN TABLE_B TBLB ON TBLA.ID = TBLB.AID
LEFT JOIN TABLE_C TBLC ON TBLB.ID = TBLC.BID
LEFT JOIN TABLE_D TBLD ON TBLC.ID = TBLD.CID
It’s relatively straight-forward but what I want to do is somewhat a conditional join in that I want all records from TABLE A but want to join TABLE B -> TABLE C -> TABLE D if the first join between TABLE A and TABLE B is satisfied, bearing in mind that I could change TABLE B -> TABLE C -> TABLE D joins to be INNER as there’ll exist in that initial join between TABLE A and TABLE B is satisfied.-
But also I’d need a WHERE condition on TABLE D also.
So essentially want to eliminate the LEFT JOIN’S between TABLE_B, TABLE_C, TABLE_D where join isn’t satisfied between TABLE_A and TABLE_B.
Very simplified data so apologies!
| Table A |
| ID |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| Table B |
| ID | AID |
| 1 | 5 |
| Table C |
| ID | BID |
| 1 | 1 |
| Table D |
| ID | CID | Value |
| 1 | 1 | ABC |
The reason I want to eliminate the join is that for 4 of the 5 rows in Table A, I’m doing unnecessary joins across three tables to get the value in Table D.
You can use brackets with join, but not sure if that would help you!
SELECT * FROM
TABLE_A TBLA
LEFT JOIN (TABLE_B TBLB
INNER JOIN TABLE_C TBLC ON TBLB.ID = TBLC.BID
INNER JOIN TABLE_D TBLD ON TBLC.ID = TBLD.CID) ON TBLA.ID = TBLB.AID
This way, when you have A matches entries in B, but B is not matched in the chain to C and D, B data is not retrieved, and so for C
You mentioned that you need a where condition on table D? Does that mean that you always have to link to D?! Note that if you have a condition on D, the condition has to be satisfied in all cases. Hence, when no records are retrieved from D, no records will be retreived from the query (even with your initial outer join unless you used OR .. is null )

Select records not in another table with additional criteria

I am working on an ACCESS DB.
I have 1 table (tblData) with 1 column ( DataId) and 3 entries:
tblData (A)
+--------+
| DataId |
+--------+
| 1 |
| 2 |
| 3 |
+--------+
Another table (tblSelections) contains 3 columns (id, dataid, userid) and has 3 entries:
tblSelections (B)
+----+--------+---------+
| id | dataid | userid |
+----+--------+---------+
| 1 | 1 | 5 |
| 2 | 2 | 5 |
| 3 | 3 | 2 |
+----+--------+---------+
How can I select the records from table A (tblData) which are not in tbl B (tblSelections) for a certain 'userid'?
For 'userid' 5 the query must return 'DataId' 3 from table A as dataid 1 & 2 are already present in table B for userid 5.
For 'userid' 2 the query must return 'DataId' 1 & 2 from table A as dataid 3 is already present in table B for userid 2.
For 'userid' 1 the query must return 'DataId' 1, 2 & 3 from table A as no records are present in table B for userid 1
Use EXISTS or IN for queries like yours:
SELECT *
FROM tblData
WHERE DataId NOT IN
(
SELECT dataid
FROM tblSelections
WHERE userid = 5
);
SELECT *
FROM tblData
WHERE NOT EXISTS
(
SELECT *
FROM tblSelections
WHERE tblSelections.dataid = tblData.DataId AND tblSelections.userid = 5
);
You can use an outer join to select all records, then put a condition in the where clause that a non-nullable column in b is null. This will give you all records in a that do not have a matching row in b according to the join conditions.
This query assumes that you have a parameter or variable named #userid that represents the user ID to search against.
select
a.*
from tblData a
left join tblSelections b on b.dataid = a.dataid and b.userid = #userid
where b.id is null

Left Outer Join, No result in final query

I'm executing the following query
Select * from A a left outer join B b on (b.id = a.id)
I'm getting one record from A and no records from B. I'm expecting one record in final select query but getting none.
Here is some sample data:
A
v_id, id, date, d_id
1, 1244578, 02-MAR-11, 1827877
B, no data presented:
e_id,id,amount
What am I doing wrong? How can I get it do like this ?
This should work fine:
Select *
from A a
left outer join B b on b."id" = a."id"
See it in action here:
SQL Fiddle Demo
This will give you:
| V_ID | ID | DATE | D_ID | E_ID | AMOUNT |
----------------------------------------------------------
| 1 | 1244578 | 02-MAR-11 | 1827877 | (null) | (null) |
You are getting one record from Table A this is because table A has only one record and Table B have no record.
In left outer join content of first table is show in result join with second table but in your case second table have no records so final result show null values for that records.