select if is null - sql

I need to make the inner join of two tables, however, wanted to know how can I resolve this situation:
If the field in the second table is NULL he do inner join with another field.
Can you give me an example?
Thanks

depends what you are trying to achieve...
CREATE TABLE #X
(
[Id] INT,
[Name] VARCHAR(100)
)
INSERT INTO #X VALUES
(1,'michaeljackson'),
(2,'jim'),
(3,'jill'),
(4,'j')
CREATE TABLE #Y
(
[Id] INT,
[AlternateId] INT,
[Score] INT
)
INSERT INTO #Y VALUES
(1,1,10),
(2,2,20),
(3,3,30),
(4,4,40),
(NULL,2,50)
--will join all of the records in #x to the null record
SELECT *
FROM #X x
INNER JOIN #Y y
ON
x.Id = COALESCE(y.Id,x.Id)
--will join just to the ID = 4 record
SELECT *
FROM #X x
INNER JOIN #Y y
ON
x.Id = COALESCE(y.Id,4)
--redirect and let join use alternative field
SELECT *
FROM #X x
INNER JOIN #Y y
ON
x.Id = COALESCE(y.Id,y.AlternateId)
--maybe you want to actually do a FULL OUTER JOIN!
SELECT *
FROM #X x
FULL OUTER JOIN #Y y
ON
x.Id = y.Id

Easiest is probalby to consider the second table as two disjoint tables like this:
select *
from a
join (
select NewKey = key1, * from b where b.key1 is null
union all
select NewKey = key2, * from b where b.key1 is not null
) b on b.NewKey = a.key

I believe the following should work adequately.
SELECT *
FROM tblA a
INNER JOIN tblB b ON (b.Col1 IS NOT NULL AND b.Col1 = a.Col1) OR (b.Col1 IS NULL AND b.Col2 = a.Col2)
If b.Col1 is not NULL then it joins on Col1, otherwise if it is NULL then it joins on Col2.

Try this:
select * from a
inner join b on
(case when b.columntojoin is null then b.alternatecolumn else b.columntojoin end)
= a.columntojoin

Related

SQL conditional joins

I have a table-valued function with joins where I want to choose which join I use depending on a local variable like:
DECLARE #type int;
Then do some logic with #type and set it to 1.
SELECT ...
FROM table t
inner join ... a on a.id = t.id and #type = 1 -- Only trigger this join if #type is 1
inner join ... b on b.id = t.id and #type = 2 -- Only trigger this join if #type is 2
So my question is: how can I choose which join to trigger depending on the value of #type (if even possible).
The reason I want to do this is that the SELECT statement is massive, and I don't want repetitive code in the script.
Use left join instead:
SELECT ...
FROM table t LEFT JOIN
a
ON a.id = t.id AND #type = 1 LEFT JOIN
b
ON b.id = t.id AND #type = 2 ;
You might need WHERE #type IN (1, 2) if you want an empty result set for other values.
You will need COALESCE() in the SELECT to combine the columns:
COALESCE(a.col1, b.col1) as col1
This should be quite efficient. However, you might want to simply use UNION ALL:
SELECT ...
FROM table t JOIN
a
ON a.id = t.id
WHERE #type = 1
UNION ALL
SELECT ...
FROM table t JOIN
b
ON b.id = t.id
WHERE #type = 2 ;
You could union your two tables within a subquery. For any similar columns (i.e. would be in the same column in the outer select) you can place them above each other, for columns unique to each source you'd need to pad the other side of the union with NULL, e.g.
SELECT t.id,
a.SimilarCol,
a.UniqueToA,
a.UniqueToB
FROM Table AS t
INNER JOIN
( SELECT a.id,
a.SimilarCol, -- Column you would want to consider the same in each table
a.UniqueToA, -- Column Unique to this table
UniqueToB = NULL -- Column Unique to the other table
FROM SomeTable AS a
WHERE #Type = 1
UNION ALL
SELECT b.id,
b.SimilarCol,
UniqueToA = NULL,
b.UniqueToB
FROM SomeOtherTable AS b
WHERE #type = 2
) AS a
ON a.id = t.id;
Example on db<>Fiddle

Select where tuple in statement

I have table with two FK UserProfile_Id and Service_Id. This table contains bit field which value I need to change.
I have two temporary tables:
First table #temp2:
EmailAddress,
UserProfile_Id
Second table #temp:
EmailAddress,
Service_Id
This statement does not work:
UPDATE MailSubscription SET BitField=1
where UserProfile_id IN ( SELECT UserProfile_Id from #temp2 )
and Service_id IN ( SELECT ServiceId from #temp)
I know why it does not work, but have no idea how to fix it to work fine.
I need to change bitField for MailSubscription where tuple(UserProfile_Id,Service_Id) is in joined #temp and #temp2, but I can not write it like this in mssql.
UPDATE M
SET M.BitField=1
from MailSubscription M
inner join #temp2 t2 on M.UserProfile_id=t2.UserProfile_Id
inner join #temp t on M.Service_id=t.ServiceId
and t.EmailAddress=t2.EmailAddress
UPDATE MailSubscription SET BitField=1
FROM #temp2
JOIN #temp on #temp2.EmailAddress=#temp.EmailAddress
WHERE MailSubscription.Service_id = #temp.ServiceId
AND MailSubscription.UserProfile_id = #temp2.UserProfile_Id
You could use a filtering join:
update m
set BitField = 1
from MailSubscription m
join #temp t1
on t1.Service_id = m.Service_id
join #temp2 t2
on t2.UserProfile_Id= m.UserProfile_Id
and t1.EmailAddress = t2.EmailAddress
Another option with EXISTS operator
UPDATE MailSubscription
SET BitField = 1
WHERE EXISTS (
SELECT 1
FROM #temp2 t2 JOIN #temp t ON t2.EmailAddress = t.EmailAddress
WHERE t2.UserProfile_Id = MailSubscription.UserProfile_Id
AND t.Service_Id = MailSubscription.Service_Id
)
I think this should help u find the answer.
Update 'Tablename'
SET Mailsubscription = 1
WHERE concat(UserProfile_Id ,".", Service_Id) IN (
SELECT concat(t.UserProfile_Id , "." , t2,Service_Id)
FROM #temp t INNER JOIN #temp2 t2
ON t2.EmailAddress = t.EmailAddress)
update MailSubscription set
BitField = 1
from MailSubscription as MS
where
exists
(
select *
from #temp2 as T2
inner join #temp as T on T.EmailAddress = T2.EmailAddress
where
T2.UserProfile_Id = MS.UserProfile_Id and
T.Service_Id = MS.Service_Id
)

Inner join 2 tables but return all if 1 table empty

I have 2 tables say A and B, and I want to do a join on them.
Table A will always have records in it.
When table B has rows in it, I want the query to turn all the rows in which table A and table B matches. (i.e. behave like inner join)
However, if table B is empty, I'd like to return everything from table A.
Is this possible to do in 1 query?
Thanks.
Yes, for results like this, use LEFT JOIN.
Basically what INNER JOIN does is it only returns row where it has atleast one match on the other table. The LEFT JOIN, on the other hand, returns all records on the left hand side table whether it has not match on the other table.
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
I came across the same question and, as it was never answered, I post a solution given to this problem somewhere else in case it helps someone in the future.
See the source.
select *
from TableA as a
left join TableB as b
on b.A_Id = a.A_Id
where
b.A_Id is not null or
not exists (select top 1 A_Id from TableB)
Here is another one, but you need to add one "null" row to table B if it's empty
-- In case B is empty
Insert into TableB (col1,col2) values (null,null)
select *
from TableA as a inner join TableB as b
on
b.A_Id = a.A_Id
or b.A_Id is null
I would use an if-else block to solve it like below:
if (select count(*) from tableB) > 0
begin
Select * from TableA a Inner Join TableB b on a.ID = b.A_ID
end
else
begin
Select * from TableA
end
Try This
SELECT t1.* FROM table1 AS t1 INNER JOIN table2 AS t2 ON t1.something = t2.someotherthing UNION SELECT * FROM table1 WHERE something = somethingelse;
This is solution:
CREATE TABLE MyData(Id INT, Something VARCHAR(10), OwnerId INT);
CREATE TABLE OwnerFilter(OwnerId INT);
SELECT *
FROM
(SELECT NULL AS Gr) AS Dummy
LEFT JOIN OwnerFilter F ON (1 = 1)
JOIN MyData D ON (F.OwnerId IS NULL OR D.OwnerId = F.OwnerId);
Link to sqlfiddle: http://sqlfiddle.com/#!6/0f9d9/7
I did the following:
DECLARE #TableB TABLE (id INT)
-- INSERT INTO #TableB
-- VALUES (some ids to filter by)
SELECT TOP 10 *
FROM [TableA] A
LEFT JOIN #TableB B
ON A.ID = B.id
WHERE B.id IS NOT NULL
OR iif(exists(SELECT *
FROM TableB), 1, 0) = 0
Now:
If TableB is empty (leave the commented lines commented) you'll get the top 10.
If TableB has some ids in it, you'll only join by those.
I do not know how efficient this is. Comments are welcome.
Maybe use a CTE
;WITH ctetable(
Select * from TableA
)
IF(EXISTS(SELECT 1 FROM TableB))
BEGIN
Select * from ctetable
Inner join TableB
END
ELSE
BEGIN
Select * from ctetable
END
or dynamic SQL
DECLARE #Query NVARCHAR(max);
SET #QUERY = 'Select * FROM TableA';
IF(EXISTS(SELECT 1 FROM TableB))
BEGIN
SET #QUERY = CONCAT(#QUERY,' INNER JOIN TableB');
END
EXEC sp_executesql #Query

t-sql insert - select - with parameters

I have a 4 tables. One of the tables we are going to be inserting data into (Table A).
Table A is going to receive misc data from Table B, C, D and also some unknown variable parameter data.
How do I set up the INSERT with a SELECT with also receiving parameters?
Something like this?
Insert INTO TableA (col1, col2,col3,col4)
SELECT b.col1, c.col2, d.col3, #myparam
FROM TableB as b
INNER JOIN TableC as c
ON b.id = c.id
INNER JOIN TableD as d
on c.id = d.id
Something like this:
DECLARE #a int, #b int
SET #a = 5
SET #b = 7
INSERT INTO TableA(Column1, Column2)
SELECT SomeOtherColumn, #a
FROM TableB
UNION
SELECT YetAnotherColumn, #b
FROM TableC

SQL Inner Join On Null Values

I have a Join
SELECT * FROM Y
INNER JOIN X ON ISNULL(X.QID, 0) = ISNULL(y.QID, 0)
Isnull in a Join like this makes it slow. It's like having a conditional Join.
Is there any work around to something like this?
I have a lot of records where QID is Null
Anyone have a work around that doesn't entail modifying the data
You have two options
INNER JOIN x
ON x.qid = y.qid OR (x.qid IS NULL AND y.qid IS NULL)
or easier
INNER JOIN x
ON x.qid IS NOT DISTINCT FROM y.qid
If you want null values to be included from Y.QID then Fastest way is
SELECT * FROM Y
LEFT JOIN X ON y.QID = X.QID
Note: this solution is applicable only if you need null values from Left table i.e. Y (in above case).
Otherwise
INNER JOIN x ON x.qid IS NOT DISTINCT FROM y.qid
is right way to do
This article has a good discussion on this issue. You can use
SELECT *
FROM Y
INNER JOIN X ON EXISTS(SELECT X.QID
INTERSECT
SELECT y.QID);
Are you committed to using the Inner join syntax?
If not you could use this alternative syntax:
SELECT *
FROM Y,X
WHERE (X.QID=Y.QID) or (X.QUID is null and Y.QUID is null)
I'm pretty sure that the join doesn't even do what you want. If there are 100 records in table a with a null qid and 100 records in table b with a null qid, then the join as written should make a cross join and give 10,000 results for those records. If you look at the following code and run the examples, I think that the last one is probably more the result set you intended:
create table #test1 (id int identity, qid int)
create table #test2 (id int identity, qid int)
Insert #test1 (qid)
select null
union all
select null
union all
select 1
union all
select 2
union all
select null
Insert #test2 (qid)
select null
union all
select null
union all
select 1
union all
select 3
union all
select null
select * from #test2 t2
join #test1 t1 on t2.qid = t1.qid
select * from #test2 t2
join #test1 t1 on isnull(t2.qid, 0) = isnull(t1.qid, 0)
select * from #test2 t2
join #test1 t1 on
t1.qid = t2.qid OR ( t1.qid IS NULL AND t2.qid IS NULL )
select t2.id, t2.qid, t1.id, t1.qid from #test2 t2
join #test1 t1 on t2.qid = t1.qid
union all
select null, null,id, qid from #test1 where qid is null
union all
select id, qid, null, null from #test2 where qid is null
Hey it is kind of late to answer that but I got the same question, what I realized is that you must have a record with the ID of 0 in you second table to make this :
SELECT * FROM Y
INNER JOIN X ON ISNULL(Y.QID, 0) = ISNULL(X.QID, 0)
to happen, it actually says if there is none, then use 0. BUT what if Y table does NOT have a record with the ID of 0?
So, I found this method, (and worked for my case):
SELECT
ISNULL(Y.QName, 'ThereIsNone') AS YTableQName
FROM
X
LEFT OUTER JOIN Y ON X.QID = Y.QID
A snapshot of my case
This way you DON'T need a record with 0 ID value in your second table (which is Y in this case and Customers in my case), OR any record at all
UPDATE:
You can also take a look at this post for better understanding.
Basically you want to join two tables together where their QID columns are both not null, correct? However, you aren't enforcing any other conditions, such as that the two QID values (which seems strange to me, but ok). Something as simple as the following (tested in MySQL) seems to do what you want:
SELECT * FROM `Y` INNER JOIN `X` ON (`Y`.`QID` IS NOT NULL AND `X`.`QID` IS NOT NULL);
This gives you every non-null row in Y joined to every non-null row in X.
Update: Rico says he also wants the rows with NULL values, why not just:
SELECT * FROM `Y` INNER JOIN `X`;
You could also use the coalesce function. I tested this in PostgreSQL, but it should also work for MySQL or MS SQL server.
INNER JOIN x ON coalesce(x.qid, -1) = coalesce(y.qid, -1)
This will replace NULL with -1 before evaluating it. Hence there must be no -1 in qid.