SQL query with Left Join to return results when the top 1 column of joined table matches column of main table - sql

I have a main table (TableA) and I'm Left Joining TableB, but I only want to include the first record of TableB where ColumnB of the two tables match. I've gotten this to work in the query below, except I also need to include the records of TableA where no matching record exists for TableB (i.e. in the query below b.ColumnA would be null). I understand why my line below "OR b.ColumnA = null" does not work, but I'm struggling to find a solution that does.
Any reasonable way to ALSO include records of TableA where no matching records exist in TableB
SELECT b.ColumnA, a.ColumnA, a.ColumnB
FROM TableA a
LEFT JOIN TableB b ON b.ColumnB = a.ColumnB
WHERE b.ColumnA = (SELECT TOP 1 bb.ColumnA FROM TableA aa LEFT JOIN TableB bb ON bb.ColumnB = a.ColumnB)
OR b.ColumnA = null

Use OUTER APPLY:
SELECT b.ColumnA, a.ColumnA, a.ColumnB
FROM TableA a OUTER APPLY
(SELECT TOP (1) b.*
FROM TableB b
WHERE b.ColumnB = a.ColumnB
ORDER BY ? -- however you are defining the ordering for "first"
) b;
You can leave out the ORDER BY if you are content with an arbitrary matching record from b. However, the question specifies "first" without defining it.

Related

What is the correct way of writing an exclusive left-join on two tables?

Do I need to write condition 'is NULL' for two (or could be more) keys when doing an exclusive left join of two tables? The question is if the 'WHERE B.columnName1 IS NULL' is enough?
Join with one key condition:
SELECT columns
FROM TableA
LEFT OUTER JOIN TableB
ON A.columnName = B.columnName
WHERE B.columnName IS NULL
Is the following more accurate? Do I need condition for columnName2?
SELECT columns
FROM TableA
LEFT OUTER JOIN TableB
ON A.columnName1 = B.columnName1
AND A.columnName2 = B.columnName2
WHERE B.columnName1 IS NULL
AND B.columnName2 IS NULL
So far it worked with one condition but I just got confused, I see this is simple question, sorry for that
Single column is enough(as long as it is not nullable):
SELECT columns
FROM TableA A
LEFT OUTER JOIN TableB B
ON A.columnName = B.columnName
WHERE B.columnName IS NULL;
Best practice is to use primary key for tableB
The ON clause contains the condition for the join:
ON A.columnName = B.columnName
If this condition is not met then the result is that all columns of the unmatched row of table B will be NULL, so your 2nd query is not wrong.
But, this also means that B.columnName itself is NULL and this condition only in the WHERE clause is enough.
It simply means that in this row A.columnName has no matching B.columnName.
The best practice is to use a column that is part of the ON clause, which your code is doing:
SELECT columns
FROM TableA A LEFT OUTER JOIN
TableB B
ON A.columnName = B.columnName
WHERE B.columnName IS NULL;
The JOIN does not treat NULL values as equal. Equally, the primary key (or any component of the primary key) also works fine.
If you don't want to think about this, use NOT EXISTS:
SELECT columns
FROM TableA A
WHERE NOT EXISTS (SELECT 1
FROM TableB B
WHERE A.columnName = B.columnName
);

SQL Multiple joins with OR condition

I have a following tables:
TableA
id
name
TableB
id
tableA_id
TableC
id
tableA_id
So tables B and C have tableA_id fk.
I need a query which will return all id-s from TableA that have reference in either TableB or TableC.
If I do standard join, it will return only values that have reference in both tables B and C.
I could do this using two queries, one joins B, other joins C and use UNION to merge results, but I dont want to write same query twice.
Is there a way to achieve this 'OR' JOIN??
Try with this
SELECT DISTINCT TABLEA.ID_A, TABLEA.NAME
FROM TABLEA,TABLEB,TABLEC
WHERE TABLEA.ID_A = TABLEB.ID_A AND TABLEA.ID_A = TABLEC.ID_A
Using DISTINCT TAG you eliminate duplicates.
Something like this?
SELECT
*
FROM
TableA,
TableB,
TableC
WHERE
TableA.id = TableB.tableA_id
OR TableA.id = TableC.tableA_id
You can use left outer joins and checks for the ids:
SELECT a.id FROM A a
LEFT JOIN B b ON a.id = b.tableA_id LEFT JOIN C c ON a.id = c.tableA_id
WHERE b.id IS NOT NULL OR c.id IS NOT NULL

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