Join where records dont match - sql-server

I need to do a join on two tables, I need EVERYTHING from table A, and just the stuff from table B where the 'REF' for each row, is not already in table A's results.
Key Facts:
Table B contains the complete amount of ID's/Names however all the other information is blank. Its basically just a table with all employee's name's and id's but its a complete list.
Table A contains a limited amount of results but all the other columns have data in them.
What I need is to use Table B as a complete reference rather than just see what exists in table A so basically:
"Show me everything from table A, and add the extra people's details
found in table B where they dont already exist in table A to give me a complete result set"
select
ID,
Name,
StartDate,
EndDate,
State,
Status,
Comment,
IsComment
from
tableA
select
ID,
Name,
StartDate,
EndDate,
State,
Status,
Comment,
IsComment
from
tableB
Table A contents:
ID Name START_DATE END_DATE STATE Status Comment Is_Comment
6760 chris 2012-09-03 2012-09-09 4 Applied 0
6524 dave 2012-09-03 2012-09-09 4 Applied 0
4268 james 2012-09-03 2012-09-09 4 Applied Friday-Off 1
7851 rob 2012-09-03 2012-09-09 4 Applied 0
Table B contents
ID Name START_DATE END_DATE STATE Status Comment Is_Comment
6760 Chris
6524 dave
4268 james
7851 rob
4521 ryan
5698 julie
4596 rory
1111 mary
5621 owain
9999 jacob
After the join what I want to see:
ID Name START_DATE END_DATE STATE Status Comment Is_Comment
6760 chris 2012-09-03 2012-09-09 4 Applied 0
6524 dave 2012-09-03 2012-09-09 4 Applied 0
4268 james 2012-09-03 2012-09-09 4 Applied Friday-Off 1
7851 rob 2012-09-03 2012-09-09 4 Applied 0
4521 ryan
5698 julie
4596 rory
1111 mary
5621 owain
9999 jacob

Try this:
select
tableB.ID,
tableB.Name,
tableA.StartDate,
tableA.EndDate,
tableA.State,
tableA.Status,
tableA.Comment,
tableA.IsComment
from
tableB
LEFT JOIN tableA on tableB.ID = tableA.ID
Because then every ID and Name will be listed from tableB, and every other column is listed from tableA.
If there is no connection between the tables, then the other columns got the NULL from TableA - because of LEFT JOIN -, if there is a connection then you get the filled values from TableA also.
Here is an SQL fiddle how this simple solution works.

Please use this SQL:
declare #tableA table
(
ID int,
Name nvarchar(250),
Age int
)
declare #tableB table
(
ID int,
Name nvarchar(250),
Age int
)
Insert #tableA values (1,'a',10);
Insert #tableA values (2,'b',20);
Insert #tableB values (1,'a',null);
Insert #tableB values (2,'b',null);
Insert #tableB values (3,'c',null);
Insert #tableB values (4,'d',null);
select tblResult.*,T1.Age from
(
select ID,Name from #tableA
union
select ID,Name from #tableB) as tblResult
left join #tableA as T1 on tblResult.ID =T1.ID

Use a Left join
SELECT [columnsListYouNeed]
FROM TableB
LEFT JOIN TableA ON TableA.ID = TableB.ID

Related

SQL Server : selecting the Max Date/time of 2 rows that have the same value in the same column

Date Id Name ClockinOrOut
-------------------------------------------------
2019-12-19 10:24:00.000 4 Bob In
2019-12-19 15:26:10.000 4 Bob Out
2019-12-19 12:17:36.000 800 Gary In
2019-12-19 08:41:21.000 800 Gary Out
I can't seem to get this output with the most recent date/time based off of Id and doesn't matter whether the ClockInOrOut is In or Out, even with using the MAX() function
Date Id Name ClockinOrOut
-------------------------------------------------
2019-12-19 15:26:10.000 4 Bob Out
2019-12-19 12:17:36.000 800 Gary In
If you want the most recent row for each id, then a convenient method is:
select t.*
from t
where t.date = (select max(t2.date)
from t t2
where t2.id = t.id
);
With an index on (id, date), this is likely to have very good performance.
Here is a solution without subquery or aggregators
SELECT
*
FROM
tracking t
LEFT JOIN tracking t2
ON t2.id = t.id
AND t2.date > t.date
WHERE t2.id is null
Here we use a left join to the same table by ID (if you want you can use more fields) and
demand that the date be greater than that of t.
the row that cannot match this, is the biggest date of that id so we use the where t2.id is null to only show the not matching rows
NOTE: if the biggest date is more that once for the same ID this query will bring all those rows.If u have a autoincremental id you can use that for the last one inserted
changing AND t.date > t2.date for AND t.autoincremental_id > t2.autoincremental_id

Left Join containing where clause INSIDE join

Lets say we have the following table structure:
DECLARE #Person TABLE
(
PersonId INT,
Name VARCHAR(50)
)
DECLARE #Address TABLE
(
AddressId INT IDENTITY(1,1),
PersonId INT
)
And we insert two person records:
INSERT INTO #Person (PersonId, Name) VALUES (1, 'John Doe')
INSERT INTO #Person (PersonId, Name) VALUES (2, 'Jane Doe')
But we only insert a address record for John
INSERT INTO #Address (PersonId) VALUES (1)
If I execute the following queries I get different results
SELECT *
FROM #Person p
LEFT JOIN #Address a
ON p.PersonId = a.PersonId AND a.PersonId IS NULL
PersonId | Name | AddressId | PersonId
1 | John Doe | NULL | NULL
2 | Jane Doe | NULL | NULL
VS
SELECT *
FROM #Person p
LEFT JOIN #Address a
ON p.PersonId = a.PersonId
WHERE a.PersonId IS NULL
PersonId | Name | AddressId | PersonId
2 | Jane Doe | NULL | NULL
Why are the queries returning different results?
The first query is not meeting any of your conditions. Hence it is displaying all results from the #Person table (Typical Left join). Where as in the second query, the where clause is applied after the join. Hence it is displaying proper result.
First:
get all records (two) from Person and join 0 records from Address, cos none of address have PersonID = NULL. After that no additional filters applyed. And you see two records from Person
Second:
get all records (two) from Person and one of them joined to Address with ID = 1. After that your WHERE filter applyed and one of records with joined ID = 1 disappears.
ON clause defines which all matching rows to show from both tables.
WHERE clause actually filters the rows.
In the 1st query, it is returning 2 rows because LEFT JOIN returns all the rows from the left table irrespective of match from right table.
2nd query is returning 1 row, because for PersonId=1, #Address table contains a matching record hence a.PersonId is NOT NULL.
Make it a habit to read your SQL query from the Where condition and then look at your joins, this will give you a clearer meaning/understanding of what is happening or going to be returned.
In this case you said WHERE a.PersonId IS NULL the Select Part must happen and It must Join using the following join criteria.
That is how your query is being read by your machine hence the different sets of results.
And then in contrast, on the condition where there is no where clause, the results on the Left table (p) do not have to exist on (a) but at the same time the results on (a) must be null but already they might not exist. Already at this point your SQL will be confused.

Select mismatch column values from database

I want to select and fetch all mismatch value of two table having same Column Name But Id, Name and City are different. I am Using Sql Server Management Studio
Table A:
id Name City
1 John karachi
2 smith Capetown
3 liza Washington
Table B:
id Name City
7 Grey Dubai
8 Clarke Texas
9 liza Washington
OUTPUT:
7 Grey Dubai
8 Clarke Texas
This has been answered hundreds and hundreds of times. Not quite sure what you mean by "having same Column Name But Id, Name and City are different" but here are a couple of example of how you can do this.
You can use a left join where tablea is null,
select b.Name
, b.City
from tableb b
left join tablea a on a.name = b.name
and a.city = b.city
where a.name is null
You can use except.
select Name
, City
from tableb
except
select Name
, City
from tablea
You can try the below query. Assuming that the id column is never null
select tb.*
from tableB tb
left join tableA ta
on tb.Name=ta.Name and tb.City=ta.City
where ta.id is NULL
Link to demo sql fiddle: http://sqlfiddle.com/#!3/250e5/1

how to select a row based on a single distinct value

If i have 4 rows and want to select rows based on a single column's distinct values and dont mind which info it uses for the rest of the row, how do i do this? There doesn't seem to be a 'distinct' function for single cols whilst maintaining rest of row data.
eg
Name, value
john 1
john 2
michael 3
michael 5
result
john 1
michael 5
note it could have been john 2 or michael 3, i dont care which row for John or Michael it uses for the rest of the values.
GROUP BY Name and use any aggregate function with the value MIN or MAX since you don't care about the value of it:
SELECT Name, MIN(value)
FROM table
GROUP BY Name
Try this
select a.* from TAbleName a
inner join
(
select distinct name,min(Id) as id from TAbleName
group by name
) as b
on a.name= b.name
and a.id=b.id

How can I add an integer from another table to the current selected table in SQL Server?

Does anyone know how can I add an integer from another table to the current selected table in SQL Server?
For example:
I have 2 tables with the following information in each table
tableA:
id username point status country
1 alvin 1 1 U.S.A
2 alvin 1 1 U.S.A
3 amy 1 0 Australia
tableB:
id username point
1 amy 1
2 alvin 1
3 ken 1
How can I sum up the total points in tableA with also add in the sum points from tableB?
I tried the following code, but seem is not working and error display:
SELECT username, (COUNT(distinct a.point) + (SELECT SUM(a.point)
FROM tableB b WHERE b.username = a.username) AS 'Points', status, country
FROM tableA
GROUP BY aco.username
And the output I expected will be:
username Points status country
alvin 3 1 U.S.A
amy 2 0 Australia
WITH Results(username,point)
AS
(
SELECT username, point FROM TableA
UNION ALL
SELECT username, point FROM TableB
)
SELECT username, sum(point) AS Points FROM Results GROUP BY username
GO
EDIT
The question has changed, so now the solution should look like this
WITH Results(username,point,status, country)
AS
(
SELECT username, point, status, country FROM TableA
UNION ALL
SELECT username, point, null, null FROM TableB
)
SELECT username, sum(point) AS Points, max(status), max(country) FROM Results GROUP BY username
GO
What is WITH ?
What is UNION ?
You don't mention why Ken doesn't appear in the output table, I assume that TableA is the 'master' list. If so I would do the following INNER JOIN which is the most simple solution.
SELECT a.username AS Username, SUM(ISNULL(a.point,0)+ISNULL(b.point,0)) as Points,
MAX(a.Status) as Status, MAX(a.Country) as Country
FROM TableA a
INNER JOIN TableB b
ON a.username=b.username
GROUP BY a.username

Resources