My attempt at LEFT JOIN isn't producing desired result. Any ideas? - sql

I am seriously suffering from brain dead as I have done this successfully several times in the past.
This time, it isn't working.
I have 2 tables, tableA and tableB
TableA has all the surmons records
TableB has some but not all surmons.
The common key between them is surmonId.
The requirement is to display the surmons from tableB where there is a match between tableA and tableB but at the same time, display ALL the surmons from tableA.
In other words, give me from tableB any records that exist and all the records on tableA.
The lef join query below is only giving me records that exist in tableB.
Select distinct l.surmons from tableB b left join tableA a on b.surmonId = a.surmonId.
There are only 10 surmons on tableB and that's all I am getting.
Where am I messing up?
Thanks a lot in advance

Either switch order of your tables:
SELECT DISTINCT a.surmons
FROM tableA a
LEFT JOIN tableB b
ON a.surmonId = b.surmonId
Or use my favorite, the RIGHT JOIN:
SELECT DISTINCT a.surmons
FROM tableB b
RIGHT JOIN tableA a
ON b.surmonId = a.surmonId

If you want everything from tableA, you need to make the left join from tableA to tableB.
Select distinct a.surmons from tableA a left join tableB b on a.surmonId = b.surmonId

Related

Join of Two Tables where Data Matches in One Column

For some reason I have a hard time grasping joins and this one should be very simple with the knowledge that I have in SQL.
Anyway, I have 2 tables. We will call them TableA and TableB. One of the columns in TableA is "ID". TableB only consists of the column "ID". I want to return all rows in TableA whose ID is present in TableB.
I know this should be very simple to figure out, but my brain doesn't want to work today.
You can do this using an EXISTS:
Select A.*
From TableA A
Where Exists
(
Select *
From TableB B
Where A.Id = B.Id
)
You can also use a JOIN if you wish, but depending on your data, you may want to couple that with a SELECT DISTINCT:
Select Distinct A.*
From TableA A
Join TableB B On A.Id = B.Id
One thing to keep in mind is that the ID of TableA is not necessarily related to the ID of TableB.
this should work
SELECT B.ID
FROM TableA A
JOIN TableB B
ON (A.ID=B.ID)
WHERE A.ID=B.ID
You can also use IN operator like this:
Select *
From TableA
Where ID in
(
Select distinct ID
From TableB
)

Joining columns from different tables without duplicating

I have the table TableA with 100 rows in it. It has a column loanid, which may have duplicates.
I need to join with the other table TableB, which has a column loanid, to join with.
But, the loanid in tableB may or may not be in tableA.
So if I take a right join or left join, I want the result to be same as 100.
Since there is a matching and unmatching loanid in both table, there is a chance of result to be not 100 rows, if I do a right join or left join.
From what you describe you want a left join:
select . . .
from tablea a left join
tableb b
on a.loanid = b.loanid;
This keeps every row in tablea along with all matching rows in tableb. From your description, tableb doesn't have duplicates, so this will keep everything in tablea with no duplicates.
If tableb had duplicates and you wanted one arbitrary row, then you can use outer apply:
select . . .
from tablea a outer apply
(select top 1 b.*
from tableb b
where a.loanid = b.loanid
) b;

Join on to table with multiple matches but only bring back specified match

I have 3 tables.
Table A contains the data that my query is going to be based on. It contains id1.
Table B is my connecting table, it contains 2 columns that I'm concerned with: id1 & id2.
Table C is my lookup table, it contains id2 and ReasonName. I need the column ‘ReasonName’ and all the data from table A.
If I do the following SQL:
SELECT NAME,
STARTDATE,
ENDDATE,
REASON,
ID1
FROM TABLEA
LEFT JOIN TABLEB
ON TABLEA.ID1 = TABLEB.ID1
I am then able to do a second join on to TableC, however this is where the problem lies.
There are multiple matches in TableC so therefore my totalrows increases. I need to avoid this.
See image for what TableC looks like:
If my SQL statement now looks like this:
SELECT TABLEA.NAME,
TABLEA.STARTDATE,
TABLEA.ENDDATE,
TABLEA.REASON,
TABLEA.ID1,
TABLEC.REASONNAME
FROM TABLEA
LEFT JOIN TABLEB
ON TABLEA.ID1 = TABLEB.ID1
LEFT JOIN TABLEC
ON TABLEB.ID2 = TABLEC.ID2
Then my rows increase by around 1000. This is because it is quite possible that TableA.id1 matches multiple id2’s found in TableC. It then duplicates rows apart from the different TableC.ReasonName.
In TableC there is one ReasonName that I am concerned with. For this example I will say it is ‘reasonf’.
What I need is to bring through ReasonName from TableC, BUT only the ones that contain reasonf, the rest I want to say NULL or to do a COALESCE with ‘No Reason’.
I have tried putting a WHERE clause into the statement. See SQL:
SELECT TABLEA.NAME,
TABLEA.STARTDATE,
TABLEA.ENDDATE,
TABLEA.REASON,
TABLEA.ID1,
TABLEC.REASONNAME
FROM TABLEA
LEFT JOIN TABLEB
ON TABLEA.ID1 = TABLEB.ID1
LEFT JOIN TABLEC
ON TABLEB.ID2 = TABLEC.ID2
WHERE TABLEC.ID2 = 'asd1f5as98a4'
But then it will only bring though those records where there is a match with ‘reasonf’, I want it to display reasonf people and ignore the rest (leave as null or something) so I have no duplicates but my full result set.
I'm thinking I may need to change to a right join or possibly change the WHERE but I'm not entirely sure.
Move your WHERE clause into the join...
select
TableA.name,
TableA.startDate,
TableA.endDate,
TableA.Reason,
TableA.id1,
COALESCE(TableC.ReasonName, 'No Reason') AS FilteredReasonName
from
TableA
left join
TableB
on TableA.id1 = TableB.id1
and TableB.id2 = 'asd1f5as98a4'
left join
TableC
on TableB.id2 = TableC.id2
Now, TableB (the source of the duplication) only joins if it is ReasonF or not at all. Then the next join goes and looks up the ReasonName for that code.
If nothing is found, the COALESCE() replaces the NULL with 'No Reason'.
If I'm understanding what you want correctly....
select
TableA.name,
TableA.startDate,
TableA.endDate,
TableA.Reason,
TableA.id1,
TableC.ReasonName
from
TableA
left join TableB on TableA.id1 = TableB.id1
left join TableC on TableB.id2 = TableC.id2 and TableC.id2 = 'asd1f5as98a4'

SQL Delete based on condition in join

It is possible to delete records based on a satisfied condition with a join query?
For instance, I have a linking table joining 3 records. The query I have at the moment deletes records from this table where one of the id's isn't IN() an imploded Php array. I've come to realise that the query should only remove records from this table if the id's don't exist in the array and they belong to a certain other table based on the a link to another table.
For SQL Server, the command is slightly different:
DELETE FROM TableA
FROM TableA LEFT OUTER JOIN TableB ON TableA.Column = TableB.Column
WHERE TableB.Column IS NULL
No, that's not a typo, yes, you do need "FROM TableA" twice. At least, you need the second FROM (the first is optional). The following has the advantage that it works for both SQL Server and MySQL:
DELETE TableA
FROM TableA LEFT OUTER JOIN TableB ON TableA.Column = TableB.Column
WHERE TableB.Column IS NULL
I like to use EXISTS clauses for this:
DELETE FROM TableA
WHERE
<<put your array condition here>>
AND NOT EXISTS
(SELECT 1 FROM TableB Where TableB.ID=TableA.ID)
You can use :
DELETE Based on a Join:
DELETE A
FROM TableA AS A
LEFT OUTER JOIN TableB As B ON A.Id = B.TabaleAId
WHERE B.Column IS NULL
Delete With SubQuery:
DELETE
FROM TableA AS A
Where
A.id not in ( Select B.TabaleAId From Tab;eB As B )
or
DELETE FROM TableA
WHERE Not EXISTS
(
SELECT *
FROM TableB As B
Where B.TableAId = TableA.Id
)
DELETE Using Table Expressions:
With A
As
(
Select TableA.*
FROM TableA AS A
LEFT OUTER JOIN TableB As B ON A.Id = B.TabaleAId
WHERE B.Column IS NULL
)
Delete From A
DELETE FROM TableA
LEFT OUTER JOIN TableB
WHERE TableB.Column IS NULL
Will delete the records in tableA that don't have a corresponding record in TableB. Is that like what you are after?
DELETE FROM a
FROM TableA AS a LEFT OUTER JOIN TableB AS b
on a.CALENDAR_DATE = b.CALENDAR_DATE AND a.ID = b.ID
Where b.ID is null
You can first use the select statement and verify your records that you want to delete and then remove the select statement and add Delete FROM tablename with the above query syntax.
The easiest way to Delete based on join is as follow:
1.Write your query using SELECT statement instead of DELETE statement
SELECT COLUMNS
FROM Table1
INNER JOIN Table2 ON Table1.YYY = Table2.XXX
2.Replace SELECT COLUMNS with DELETE FROM TABLE
DELETE FROM Table1
FROM Table1
INNER JOIN Table2 ON Table1.YYY = Table2.XXX
Note that we need to specify FROM twice, one for DELETE part and one for JOIN part.
delete from TableA
where id in
(
select id from TableA
except select id from TableB
)
Which means "delete from tableA where id in table a but not in table b)
Otherwise a Merge statement might help you (when matched/not matched delete etc)
http://technet.microsoft.com/en-us/library/bb510625.aspx

How do I get all records from tableA with a left outer join and a where condition on tableB?

Basically, what I want is if there is a record in tableB of type 'X' I want to see it, otherwise I don't, but I want all records from tableA.
I know I could accomplish this by putting the tableB.type = 'X' in the LEFT OUTER JOIN ON clause, but I can't do that because I'm limited to using only the where condition because I'm using a restricted query manager of a program I won't name, but I definitely hate. :)
SELECT *
FROM tableA
LEFT OUTER JOIN ON tableA.ID = tableB.ID
WHERE tableB.type = 'X'
How do I accomplish this?
EDIT
I've tried this, but I still don't get all records from tableA. I'm testing this on SQL server to avoid waiting for long periods for my query to run on the production system. I'm pretty sure the production system is using Oracle if that helps.
SELECT *
FROM tableA LEFT OUTER JOIN ON tableA.ID = tableB.ID
WHERE tableB.type = 'X' OR tableB.type IS NULL
Check for nulls in tableB:
SELECT *
FROM tableA LEFT OUTER JOIN ON tableA.ID = tableB.ID
WHERE tableB.type = 'X'
OR tableB.type IS NULL
That will get you everything from both tables when the join matches, and everything from tableA when there's no corresponding record in tableB.
If type can be null naturally, you'll want to change the condition to something more sound:
SELECT *
FROM tableA LEFT OUTER JOIN ON tableA.ID = tableB.ID
WHERE tableB.type = 'X'
OR tableB.ID IS NULL
Assuming ID is the primary key and cannot be null naturally, that will get the same result.
Don't know if you have access to the database, or if you have to query tableB specifically due to some other restriction, but you could always create a view of table b called tableBTypeX where the view is restricted to only those rows with type = x. Then you could left outer join against tableBTypeX . In your query, the join columns are ID columns, so they probably have indexes, making the query fine in terms of speed. In the case where the join columns are not indexed, joining against the view would be more efficient, because fewer rows are joined against, and joining against unindexed rows usually requires a full table scan, making it a much more time consuming query.
You can join against the "type X" records from tableB exclusively by amending the join condition:
SELECT
*
FROM
tableA
LEFT OUTER JOIN ON
tableA.ID = tableB.ID
AND tableB.type = 'X'
Is UNION possible?
SELECT *
FROM tableA
LEFT OUTER JOIN ON tableA.ID = tableB.ID
WHERE tableB.type = 'X'
UNION
SELECT *
FROM tableA
... or a CTE? Not sure how the name tableB would resolve though and can't test...
;WITH tableB AS
(
SELECT * FROM tableB WHERE type = 'X'
)
SELECT *
FROM
tableA
LEFT OUTER JOIN
tableB ON tableA.ID = tableB.ID