SQL left JOIN with where clause not returning all results - postgresql

I have 2 tables that I join using an ID. I want all the data from my main table to show and match if that ID is in table #2 to show a few more columns in my output. That currently works with
select table1.id, table1.name, table1.phone, table1.address,
table2.loyalcustomer, table2.loyaltynumb, table2.loyaltysince from table1
left join table2
ON table1.id = table2.table1id
What I'm trying to do is the same thing, but add a WHERE clause to table2.loyalcustomer != 'Yes'. When I do that, it doesn't return all the data from my main table (table1), but instead only shows what matches between table1 and table2. Also, table2 does not have all the info, only what was inserted into the table.
select table1.id, table1.name, table1.phone, table1.address,
table2.loyalcustomer, table2.loyaltynumb, table2.loyaltysince from table1
left join table2
ON table1.id = table2.table1id
WHERE table2.loyalcustomer != 'Yes'
Been reading about different joins but what i've been reading is that my where statement may be contradicting my join and I'm not sure how to resolve that.
SQL DB: Postgres

The problem is on your WHERE clause. Be carefull with LEFT JOINS !
When you do a LEFT JOIN on a TABLE, this table wont filter the results as if it was an INNER JOIN. This is because you accept your LEFT JOIN TABLE to return entire NULL rows.
However, you are using a COLUMN from your "LEFT JOINED TABLE" in your WHERE clause when you say... "table2.loyalcustomer != 'Yes'" . This clause works when table2.loyalcustomer is not not null but it DOESN'T work if table2.loyalcustomer is NULL.
So here it goes the right way to do it :
select table1.id, ...
from table1
left join table2 ON table1.id = table2.table1id and table2.loyalcustomer != 'Yes'
Here it goes an alternative way to do it...
select table1.id, ...
from table1
left join table2 ON table1.id = table2.table1id
WHERE ISNULL(table2.loyalcustomer, '') != 'Yes'
To resume : NULL != 'Yes' doesn't work. You need something different from null to evaluate your expression.

Try this one man
SELECT table1.id, table1.name, table1.phone, table1.address,
table2.loyalcustomer, table2.loyaltynumb, table2.loyaltysince FROM users
LEFT JOIN table2
ON table1.id = table2.table1id
HAVING table2.loyalcustomer != 'Yes'

Related

If transaction_id is not null join on transaction_id else join on user id - in same join?

I would like to do a single left join from table a onto table b on transaction_id
select a.*, b.*
from tablea a
left join tableb b on b.transaction_id = a.transaction_id
However, there are cases where transaction id on either table is missing, in which case I would like to fall back onto joining on a.user_id = b.user_id. If user_id is also missing then fine, I still want to keep all records from a.
Is there a way I can tell postgres to try joining on one field and if it's missing on either table to then try joining on another field?
Is there a way to do this?
Add a 2nd join to tableb with the condition that the 1st join did not match:
select a.*,
coalesce(b1.col1, b2.col1), coalesce(b1.col2, b2.col2), .....
from tablea a
left join tableb b1 on b1.transaction_id = a.transaction_id
left join tableb b2 on b2.user_id = a.user_id and b1.transaction_id is null

I want to join 3 tables and select 1 coulmn from each table

I have tried using join as follows but it is not working
SELECT distinct(udf.FIELD_NAME),fun.FUNCTION_ID,mo.MODULE AS PRODUCT_MODULE FROM TABLE1 udf
JOIN TABLE2 mo
ON udf.PRODUCT_CODE = mo.PRODUCT_CODE
JOIN TABLE3 fun
ON udf.FIELD_NAME = fun.FIELD_NAME
where (udf.product_code in (select mo.product_code from TABLE2 mo))AND(udf.FIELD_NAME like '%UDF%')AND(udf.FIELD_NAME IN(SELECT fun.FIELD_NAME FROM TABLE3 fun));
I want all the where conditions mentioned here to work
There are some statements in your WHERE clause that mimic the join condition. If you do a join like this
JOIN TABLE2 mo
ON udf.PRODUCT_CODE = mo.PRODUCT_CODE
then there is no need to add the WHERE clause
where (udf.product_code in (select mo.product_code from TABLE2 mo))
because those 2 do the same. Unless you have duplicate rows, the "DISTINCT" clause is not needed either. Your query can be rewritten as:
SELECT
udf.field_name,
fun.function_id,
mo.module AS product_module
FROM
table1 udf
JOIN table2 mo ON udf.product_code = mo.product_code
JOIN table3 fun ON udf.field_name = fun.field_name
WHERE
udf.field_name LIKE '%UDF%';

What's the difference between these joins?

What's the difference between
SELECT COUNT(*)
FROM TOOL T
LEFT OUTER JOIN PREVENT_USE P ON T.ID = P.TOOL_ID
WHERE
P.ID IS NULL
and
SELECT COUNT(*)
FROM TOOL T
LEFT OUTER JOIN PREVENT_USE P ON T.ID = P.TOOL_ID AND P.ID IS NULL
?
The bottom query is equivalent to
SELECT COUNT(*)
FROM TOOL T
since it is not limiting the result set but rather producing a joined table with a lot of null fields for the right part of the join.
The first query is a left anti join.

How to write a select case join?

I am trying to some sql code that combines information from 2 tables and uses case but it is not returning all the data.
SELECT TABLE1.PRODUCT, TABLE1.TYPE, TABLE1.AMOUNT,
(CASE
WHEN TABLE1.PRODUCT = 'RADIO'
THEN 100
ELSE 200
END) AS PRODUCT_CODE,
(CASE
WHEN TABLE1.TYPE = 'NEW'
THEN 'Y'
ELSE TABLE2.AGE
END) AS STATUS
FROM TABLE1 LEFT JOIN TABLE 2 ON TABLE1.TID = TABLE2.TID
WHERE TABLE1.DATE > '01-AUG-15'
AND TABLE2.DATE = '02-AUG-15'
The problem I am having is that I need all records from table1 and those that apply from table2 but when the query is returning less rows than there are in table 1.
Your problem is here
AND TABLE2.DATE = '02-AUG-15'
If Table2.Date is null due to the left join, this condition fails, which is why you are getting less rows than Table1. Adding a condition to the where clause from a left joined table is effectively turning it into an inner join.
Try either
AND (TABLE2.DATE = '02-AUG-15' OR TABLE2.DATE IS NULL)
(this assumes that TABLE2.DATE is not nullable) or put the condition in the join statement instead
FROM TABLE1 LEFT JOIN TABLE 2 ON TABLE1.TID = TABLE2.TID AND TABLE2.DATE = '02-AUG-15'

Is it possible to JOIN with a var from a LEFT JOIN without destrorying rows?

My code generates a large query. A simple version is
SELECT * FROM main_table as mt
JOIN user_data AS ud ON mt.user_id=ud.id
LEFT JOIN ban_Status AS bs ON ud.status_id=bs.id
JOIN AnotherTable ON bs.data=AnotherTable.id
NOTE: This code is untested.
When i remove the last join i get results. I can also change it to left join but that would be wrong. If ud.status is not null i would like a join as i always do when i do a select query from ban_Status. How do i fix this? must i write left join on every table if i left join the parent table? would that not give me side effects?
I am using sqlite ATM but will switch to tsql
Use the LEFT JOIN, but in your WHERE clause specify that either both ud.status_id is null and AnotherTable.id is null or neither is null.
SELECT * FROM main_table as mt
JOIN user_data AS ud ON mt.user_id=ud.id
LEFT JOIN ban_Status AS bs ON ud.status_id=bs.id
LEFT JOIN AnotherTable ON bs.data=AnotherTable.id
WHERE (ud.status_id is null and AnotherTable.id is null)
or (ui.status_id is not null and AnotherTable.id is not null)
That will keep you from selecting any records that have a ban_Status but don't have the additional data from the other table.