left join not showing null values - sql-server

I need to find the items that exist in table A but not in table B. Now that would be really simple in MySQL doing a join like this
select * from A
left join B on A.key=B.key
where B.key is null
However for some reason this is not working in MSSQL. I have created the query without the where clause to see all the results and I only see matches, not null values. Do you have any idea why this is not working?
I know I can alternatively use "when not exists" but I want to know the reason as to why with a join is not working.
I am adding the code for your review
select Absences.CustomerID, b.*
from (
select * from openquery(JUAN_INTERFACE,'select cmp_wwn from Planet_Customers where i_outcome =4')) b
left join Absences on Absences.CustomerID = b.cmp_wwn
where Absences.Type = 3223

Your where clause is filtering out null values:
where Absences.Type = 3223
You are left-joining from the openquery subquery to Absences; and then filtering only rows that have a specific (non-null) value in an Absences column.
Did you mean to join the other way around, from Absenses to openquery?

Related

Looking up values in multiple tables with multiple joins

How would you do a Select statement to lookup a value in a table and then use that value to lookup another value in another table which is then used to lookup a third value in a third table? I cannot do a join from my initial table as there is no common matching field to do the join on.
In my initial table I have an Instr_Id value which is the only possible way to eventually get the Legal_Id value but the table where the Legal_Id is stored does not have an Instr_Id value. In order to do this I need to look up multiple values from 2 other tables to eventually get to the INSTR_ID value.
Example:
I use INSTR_ID in tbl.ABC and join to INSTR_ID in tbl.DEF in order to get the Fin_Enty_Name value in tbl.DEF I then need to use this Fin_Enty_Name value to join to tbl.GHI to get the Fin_Enty_Id . I finally then need to use this Fin_Enty_Id to look up the LEGAL_ID in tbl.JKL so that I can show the LEGAL_ID for each INSTR_ID in my Select query results.
select
a.INSTR_ID,
d.LEGAL_IT
from tbl.ABC as A
Inner join tbl.DEF as B on A.INSTR_ID = B.INSTR_ID
It looks pretty much straight forward:
select a.instr_id, d.legal_id
from tbl.abc a
join tbl.def b
on a.instr_id = b.instr_id
join tbl.ghi c
on b.fin_enty_name = c.fin_enty_name
join tbl.jkl d
on c.fin_enty_id = d.fin_enty_id

Rows 'not in' and rows 'in' does not equal total rows in table

I still have much to learn in database work, so please be kind.
I am attempting to combine two tables that have similar data, but wanted to be sure that I wasn't duplicating any entries. I decided to use the query below to see how many names were already in the target table
select A.Name
From SourceTable A
where Name NOT IN
(
select B.Name
From [Production].[dbo].[DestinationTable] B
)
This returned 0 rows, so I assumed that every Name was already in the target table. But when I changed the query to
select A.Name
From SourceTable A
where Name IN
(
select B.Name
From [Production].[dbo].[DestinationTable] B
)
I got back about half of the total rows in the source table. How can these two totals not add up to the total number of rows in the source table? I assumed duplicate names, but the numbers still don't add up. What could I be missing here?
Kamil's answer is a good explanation of what's going on with IN and NOT IN. But a better way to see if your destination table is missing any names from the source table would be to use a LEFT JOIN and check for NULL.
The query would look like this:
SELECT A.Name
FROM SourceTable A
LEFT JOIN [Production].[dbo].[DestinationTable] B ON A.Name = B.Name
WHERE B.Name IS NULL
This would return all names from your source that aren't in your destination.
The reason you are not getting the total row count from both queries combined is because you have NULL values in your DestinationTable.
Generally you are ommitting checking for null values and this is the reason. You could add OR name is null to see it.
Check it using
select count(*) from destinationtable where name is null
Alternatively you could perform a CROSS JOIN and see for yourself where the data doesn't match and inspect why

Join Query Combining Two Tables

I need to display 3 columns from table A and one column from table B. I used the following join query to combine them but not getting the value in the expected columns.
example1 -this is working.(If I display one column from table A and one column from table B it works)
SELECT
tableA.col1(fkid),
tableB.col1
FROM tableA
INNER JOIN tableB
ON tableA.fkid = tableB.pkid;
I need to display 3 columns from table A and one column from table B the below query is not working.
SELECT
tableA.col1,
tableA.col2,
tableA.col3,
tableB.col1
FROM tableA
FULL JOIN tableB
ON tableA.fkid = tableB.pkid;
Original query:
select device.name,device.description, device.fkphonetemplate,phonetemplate.name from device inner join phonetemplate ON device.fkphonetemplate=phonetemplate.pkid;
Result:
description fkphonetemplate name
Nikhil (nkalantr) 10ce46f6-615d-4605-9f42-454225df5647 ARRAY(0xc7153b0)
Expected result should be:
description fkphonetemplate name
Nikhil (nkalantr) 10ce46f6-615d-4605-9f42-454225df5647 Standard 7960 SCCP
I don't get name from device table in the result and the name from phonetemplate table shows something as Array0X... but I need to get the name of phonetemplate like Standard 7960 as shown in expected result.
Can you refine my query or suggest what's wrong with the 2nd query?
Any reason for you to using full join instead of inner join ?
If no,try using inner join.
SELECT
a.col1,
a.col2,
a.col3,
b.col1
FROM tableA a
INNER JOIN tableB b
ON a.fkid = b.pkid;
Can you provide your database sample data , so we can clearly know what your need.

MSSQL - Join tables and return user based on value in another table column

probably a badly worded question so apologies.
I have 3 tables that I want to join together.
I have created an SQLFiddle here
What I am wanting, is to compare the MAXLINEDISCOUNT from the linkloads table to the allowed discounts in the price_escalation_bands table.
so in the data, the maxlinediscount of 40 must match the next highest discount in the price_escalation_bands table where the customer_band is the same.
so I want the result to match row 1, where it is bronze and discount is 45. should my MAXLINEDISCOUNT be greater than 45, then go to the next highest which could be 50 in this case.
when it matches, return the fk_salesman_userid field and match this to the username in the users table.
Obviously, all this data is dynamic so needs to look at next highest...
Currently, it is returning as blank so dont think my syntax is quite correct.
my query is:
select price_authorized,load_number,maxlinediscount,customer_band,[price_escalation_bands].fk_salesman_userid,Users.firstname firstname,totalcost,period,creditlimit,currentbalance,customername,totalcubes,treatedcubes,normalcubes,pricingissue from #linkloads
left outer JOIN [price_escalation_bands] on [price_escalation_bands].band=#linkloads.customer_band
AND price_escalation_bands.discount = (
SELECT top 1 [price_escalation_bands].[discount]
FROM [price_escalation_bands]
WHERE [price_escalation_bands].band=#linkloads.customer_band
AND [price_escalation_bands].[discount]<=#linkloads.maxlinediscount
ORDER BY [price_escalation_bands].[discount]
)
left outer join Users
on Users.userid=[price_escalation_bands].fk_salesman_userid
Help, appreciated as always.
This lists all price_escalation_bands entries over the matching limit in linkloads:
select u.username
, peb.band
, peb.discount
, ll.maxlinediscount
from price_escalation_bands peb
join Users u
on peb.fk_salesman_userid = u.UserID
join linkloads ll
on ll.customer_band = peb.band
where ll.maxlinediscount < peb.discount
Your SQL Fiddle example with this query.

Is it possible to perform a join in Access on a second column if the first is blank?

I have this ugly source data with two columns, let's call them EmpID and SomeCode. Generally EmpID maps to the EmployeeListing table. But sometimes, people are entering the Employee IDs in the SomeCode field.
The person previously running this report in Excel 'solved' this problem by performing multiple vlookups with if statements, as well as running some manual checks to ensure results were accurate. As I'm moving these files to Access I am not sure how best to handle this scenario.
Ideally, I'm hoping to tell my queries to do a Left Join on SomeCode if EmpID is null, otherwise Left Join on EmpID
Unfortunately, there's no way for me to force validation or anything of the sort in the source data.
Here's the full SQL query I'm working on:
SELECT DDATransMaster.Fulfillment,
DDATransMaster.ConfirmationNumber,
DDATransMaster.PromotionCode,
DDATransMaster.DirectSellerNumber,
NZ([DDATransMaster]![DirectSellerNumber],[DDATransMaster]![PromotionCode]) AS EmpJoin,
EmployeeLookup.ID AS EmpLookup,
FROM FROM DDATransMaster
LEFT JOIN EmployeeLookup ON NZ([DDATransMaster]![DirectSellerNumber],[DDATransMaster]![PromotionCode]) = EmployeeLookup.[Employee #])
You can create a query like this:
SELECT
IIf(EmpID Is Null, SomeCode, EmpID) AS join_field,
field2,
etc
FROM YourTable
Or if the query will always be used within an Access session, Nz is more concise.
SELECT
Nz(EmpID, SomeCode) AS join_field,
field2,
etc
FROM YourTable
When you join that query to your other table, the Access query designer can represent the join between join_field and some matching field in the other table. If you were to attempt the IIf or Nz as part of the join's ON clause, the query designer can't display the join correctly in Design View --- it could still work, but may not be as convenient if you're new to Access SQL.
See whether this SQL gives you what you want.
SELECT
dda.Fulfillment,
dda.ConfirmationNumber,
dda.PromotionCode,
dda.DirectSellerNumber,
NZ(dda.DirectSellerNumber,dda.PromotionCode) AS EmpJoin,
el.ID AS EmpLookup
FROM
DDATransMaster AS dda
LEFT JOIN EmployeeLookup AS el
ON NZ(dda.DirectSellerNumber,dda.PromotionCode) = el.[Employee #])
But I would use the Nz part in a subquery.
SELECT
sub.Fulfillment,
sub.ConfirmationNumber,
sub.PromotionCode,
sub.DirectSellerNumber,
sub.EmpJoin,
el.ID AS EmpLookup
FROM
(
SELECT
Fulfillment,
ConfirmationNumber,
PromotionCode,
DirectSellerNumber,
NZ(DirectSellerNumber,PromotionCode) AS EmpJoin
FROM DDATransMaster
) AS sub
LEFT JOIN EmployeeLookup AS el
ON sub.EmpJoin = el.[Employee #])
What about:
LEFT JOIN EmployeeListing ON NZ(EmpID, SomeCode)
as your join, nz() uses the second parameter if the first is null, I'm not 100% sure this sort of join works in access. Worth 20 seconds to try though.
Hope it works.
You Could use a Union:
SELECT DDATransMaster.Fulfillment,
DDATransMaster.ConfirmationNumber,
DDATransMaster.PromotionCode,
DDATransMaster.DirectSellerNumber,
EmployeeLookup.ID AS EmpLookup
FROM DDATransMaster
LEFT JOIN EmployeeLookup ON
DDATransMaster.DirectSellerNumber = EmployeeLookup.[Employee #]
where DDATransMaster.DirectSellerNumber IS NOT NULL
Union
SELECT DDATransMaster.Fulfillment,
DDATransMaster.ConfirmationNumber,
DDATransMaster.PromotionCode,
DDATransMaster.DirectSellerNumber,
EmployeeLookup.ID AS EmpLookup
FROM DDATransMaster
LEFT JOIN EmployeeLookup ON
DDATransMaster.PromotionCode = EmployeeLookup.[Employee #]
where DDATransMaster.DirectSellerNumber IS NULL;

Resources