Ignore SQL INNER JOIN if specific record exist? - sql

i got two table joined like this
SELECT A.id,B.status
FROM TableA A
INNER JOIN TableB B on (A.TableA_ID=B.TableA_ID)
WHERE B.status not in ('CO','CL');
I want to display results of two table joined but with condition if the status of TableB has anything in ('CO','CL') the whole join with id of TableA would be ignored not just the rows with status not in ('CO','CL').
A.id and A.TableA_ID are different columns
Original result without where condition would be like this:
+------+-----------+
| id | status |
+------+-----------+
| 1000 | RE |
| 1000 | RE |
| 1000 | RE |
| 1000 | CO |
| 2000 | RE |
| 2000 | RE |
+------+-----------+
My Result:
+------+-----------+
| id | status |
+------+-----------+
| 1000 | RE |
| 1000 | RE |
| 1000 | RE |
| 2000 | RE |
| 2000 | RE |
+------+-----------+
What i want:
+------+-----------+
| id | status |
+------+-----------+
| 2000 | RE |
| 2000 | RE |
+------+-----------+
Couldn't figure out how to do eliminate the whole join if the record 'CO' exist.

You could use not exists:
SELECT A.id,B.status
FROM TableA A
INNER JOIN TableB B on (A.TableA_ID=B.TableA_ID)
WHERE NOT EXISTS (
SELECT null
FROM TableB B
WHERE B.TableA_ID=A.TableA_ID
AND B.status in ('CO','CL')
);
Or if you only want to hit the tables once you could use an analytic count of the of the statuses you don't want to see, and eliminate any IDs with a non-zero count:
SELECT id, status
FROM (
SELECT A.id,B.status,
COUNT(case when B.status in ('CO','CL') then 1 end)
OVER (partition by A.id) AS cnt
FROM TableA A
INNER JOIN TableB B on (A.TableA_ID=B.TableA_ID)
)
WHERE cnt = 0;
db<>fiddle
This assumes A.id and A.TableA_ID are different columns; if they're the same then you don't need to look at table A directly at all, if you only want those two columns anyway - all of the information you need is in table B anyway.

here is one way :
SELECT A.id,B.status
FROM TableA A
INNER JOIN TableB B on (A.TableA_ID=B.TableA_ID)
WHERE not exists ( select 1 from TableB B where A.TableA_ID=B.TableA_ID and B.status in ('CO','CL')

Related

Get left table data completely even when there is no reference in right joined table

Database used: SQL Server
I have three tables A,B,C.
TABLE A:
------------------
| ID | Name |
------------------
| 1 | X |
------------------
| 2 | Y |
------------------
TABLE B:
----------------------
| ID | Date |
----------------------
| 1 | 2019-11-06 |
----------------------
| 2 | 2019-11-05 |
----------------------
TABLE C:
----------------------------------
| ID | B.ID | A.ID | Amount |
----------------------------------
| 1 | 1 | 1 | 500 |
----------------------------------
| 2 | 2 | 2 | 1000 |
----------------------------------
The result I would like to get is all entries of table A.Name with their amount in table C.amount where table B.Date = 2019-11-06. The result set should include all A.name entries even it have no reference in Table C.
Required result is:
-----------------------
| A.Name | C.Amount |
-----------------------
| X | 500 |
-----------------------
| Y | NULL |
-----------------------
Code I tried with :
SELECT A.Name,C.Amount
FROM A
LEFT OUTER JOIN C ON C.A_ID=A.ID
LEFT OUTER JOIN B ON B.ID = C.B_ID ON
WHERE B.Date='2019-11-06'
The result I obtained with above code is :
------------------
| Name | Amount |
------------------
| X | 500 |
------------------
There is no Y in the result, its because there is no entry for Y on that particular date. I just want to show Y and amount as null or zero.
SQL Fiddle with my query
Please help me with this.
There's is no relationship between your A and B, so we need to group B and C using a subquery to filter with date before doing the left join.
SELECT A.Name, t1.Amount
FROM A
LEFT JOIN
(SELECT C.A_ID, C.Amount FROM C
INNER JOIN B ON B.ID = C.B_ID
WHERE B.Date='2019-11-06') t1
ON t1.A_ID=A.ID
see dbfiddle
Try this-
Fiddle Here
SELECT A.Name,C.Amount
FROM A
LEFT JOIN B ON A.ID = B.ID AND B.Date = '2019-11-06'
LEFT JOIN C ON B.ID = C.ID
Output is-
Name Amount
X 500
Y (null)

How to exclude entire Customer ID data based on a condition

I need to exclude all data relating to Customer ID's that have at least one instance where a condition applies. For instance:
This is all my data with conditions
+-------------+----------------+
| Customer ID | Condition |
+-------------+----------------+
| 1 | Contacted |
| 1 | No Answer |
| 1 | Left Voicemail |
| 1 | Spoke to |
| 2 | No Answer |
| 2 | Left Voicemail |
| 3 | Spoke to |
| 3 | No Answer |
| 4 | Contacted |
| 4 | Left Voicemail |
+-------------+----------------+
I need to exclude data with conditions equal to 'Contacted'. Currently, I am using the below code and getting the following results:
SELECT a.customerID,
c.condition
FROM Tablea a
JOIN Tablec c ON
c.customerID = a.customerID
WHERE c.condition NOT LIKE 'Contacted'
+-------------+----------------+
| Customer ID | Condition |
+-------------+----------------+
| 1 | No Answer |
| 1 | Left Voicemail |
| 1 | Spoke to |
| 2 | No Answer |
| 2 | Left Voicemail |
| 3 | Spoke to |
| 3 | No Answer |
| 4 | Left Voicemail |
+-------------+----------------+
However, I would like to exclude all of the Customer ID rows if the Customer ID has the condition. Ideally the code would produce the following:
+-------------+----------------+
| Customer ID | Condition |
+-------------+----------------+
| 2 | No Answer |
| 2 | Left Voicemail |
| 3 | Spoke to |
| 3 | No Answer |
+-------------+----------------+
Any help is greatly appreciated!
This will get you the results you are looking for:
Select customerid, condition from
Tablec c
WHERE customerid NOT IN
(
Select customerid from
Tablec
WHERE condition LIKE 'Contacted'
)
In your above example I am uncertain as to why you are joining to Tablea, as you aren't pulling any data from that table except for customerID, which is already in Tablec.
However if you wanted to do the join, you could do:
Select a.customerID, c.condition from Tablea a
JOIN Tablec c ON c.customerID = a.customerID
WHERE c.customerid NOT IN
(
Select customerid from
Tablec
WHERE condition LIKE 'Contacted'
)
Here's one option using not exists:
select customerid, condition
from Tablec c
where not exists (
select 1
from Tablec c2
where c.customerid = c2.customerid and c2.condition = 'Contacted'
)
This only uses Tablec since it appears to have both customerid and condition. You can always join it back to TableA as needed.
This is slightly hacky but I'm not sure what you're original dataset looks like.
SELECT a.customerID,
c.condition
FROM Tablea a
INNER JOIN Tablec c ON
c.customerID = a.customerID
WHERE c.customerID NOT IN
(
SELECT a2.customerID
FROM Tablec a2
WHERE a2.condition = 'Contacted'
)

select query joining two tables on a range

I have two tables:
Table A with columns
name | tag | price | ref
and Table B with columns:
id | time | min_ref | max_ref
I want to make the following query, take all columns from table A and columns id and time from Table B, combining rows in such a way that particular row from A is merged with a row from B if value ref from A is in the range (min_ref, max_ref). Example:
A
name | tag | price | ref
A | aaa | 78 | 456
B | bbb | 19 | 123
C | ccc | 5 | 789
B
id | time | min_ref | max_ref
0 | 26-01-2019 | 100 | 150
1 | 27-01-2019 | 450 | 525
2 | 25-01-2019 | 785 | 800
the query should return:
name | tag | price | ref | id | time
A | aaa | 78 | 456 | 1 | 27-01-2019
B | bbb | 19 | 123 | 0 | 26-01-2019
C | ccc | 5 | 789 | 2 | 25-01-2019
The notation (min_ref, max_ref) for ranges signifies exclusive bounds. Would be [min_ref, max_ref] for inclusive.
So:
select a.*, b.id, b.time
from a
join b on a.ref > b.min_ref
and a.ref < b.max_ref;
The BETWEEN predicate treats all bounds as inclusive.
I think this is just a join:
select a.*, b.id, b.time
from a join
b
on a.ref between b.min_ref and b.max_ref;
You want a JOIN which combines rows from the two tables with an appropriate criteria. For instance:
SELECT a.name, a.tag, a.price, a.ref, b.id, bi.time
FROM a
INNER JOIN b ON b.min_ref <= a.ref AND b.max_ref >= a.ref
The INNER JOIN finds matching rows from the two tables, ON a specified criteria. In this case, the criteria is that a.ref is between b.min_ref and b.max_ref.
You can also use the sql BETWEEN operator to simplify the conditionals:
SELECT ...
FROM a
INNER JOIN b ON a.ref BETWEEN b.min_ref AND b.max_ref

Access Queries comparing two tables

I have two tables in Access, Table A and Table B:
Table MasterLockInsNew:
+----+-------+----------+
| ID | Value | Date |
+----+-------+----------+
| 1 | 123 | 12/02/13 |
| 2 | 1231 | 11/02/13 |
| 4 | 1265 | 16/02/13 |
+----+-------+----------+
Table InitialPolData:
+----+-------+----------+---+
| ID | Value | Date |Type
+----+-------+----------+---+
| 1 | 123 | 12/02/13 | x |
| 2 | 1231 | 11/02/13 | x |
| 3 | 1238 | 10/02/13 | y |
| 4 | 1265 | 16/02/13 | a |
| 7 | 7649 | 18/02/13 | z |
+----+-------+----------+---+
All I want are the rows from table B for IDs not contained in A. My current code looks like this:
SELECT Distinct InitialPolData.*
FROM InitialPolData
WHERE InitialPolData.ID NOT IN (SELECT Distinct InitialPolData.ID
from InitialPolData INNER JOIN
MasterLockInsNew
ON InitialPolData.ID=MasterLockInsNew.ID);
But whenever I run this in Access it crashes!! The tables are fairly large but I don't think this is the reason.
Can anyone help?
Thanks
or try a left outer join:
SELECT b.*
FROM InitialPolData b left outer join
MasterLockInsNew a on
b.id = a.id
where
a.id is null
Simple subquery will do.
select * from InitialPolData
where id not in (
select id from MasterLockInsNew
);
Try using NOT EXISTS:
SELECT Distinct i.*
FROM InitialPolData AS i
WHERE NOT EXISTS (SELECT 1
FROM MasterLockInsNew AS m
WHERE m.ID = i.ID)

join table in sqlalchemy with filtering by groups

table A must be outer-joinned with B.
A
id | ...
---|-----
1 |
2 |
3 |
---|-----
B
id| a_id | b | ...
--|------|----------
1 |1 | special |
2 |1 | normal |
3 |2 | normal |
4 |2 | normal |
--------------------
so I want:
A.outerjoin(B)
like this:
a_id | b.id | ...
-----|------|--------
2 | 3 |normal |
2 | 4 |normal |
3 | None |
-----|------|
what should i use to filter entire group of B with the same a_id having at least one "special" value?
I dont want lose outerjoin - None for a.id = 3.
my first idea is to use nested select, but it's not optimal.
select distinct a.*
from a join b on a.id=b.a_id
where b.b='special';
excludes a groups with 'special'
select a.*
from a outer join
(select distinct a.*
from a join b on a.id=b.a_id
where b.b='special') excluded on a.id=excluded.id
having excluded.id is null;
leaves only valid a rows.
select *
from (select a.*
from a outer join
(select distinct a.*
from a join b on a.id=b.a_id
where b.b='special') excluded on a.id=excluded.id
having excluded.id is null) outer join b on a.id=b.a_id;
valid rows outer joined with b