Conditional Inner Join - sql

I want to be able to inner join two tables based on the result of an expression.
What I've been trying so far:
INNER JOIN CASE WHEN RegT.Type = 1 THEN TimeRegistration ELSE DrivingRegistration AS RReg
ON
RReg.RegistreringsId = R.Id
RegT is a join I made just before this join:
INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id
This SQL-script does not work.
So all in all, if the Type is 1, then it should join on the table TimeRegistration else it should join on DrivingRegistration.
Solution:
In my select statement I performed the following joins:
INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id
LEFT OUTER JOIN TimeRegistration AS TReg ON TReg.RegistreringsId = R.Id AND RegT.Type = 1
LEFT OUTER JOIN DrivingRegistration AS DReg ON DReg.RegistreringsId = R.Id AND RegT.Type <>1
Then I edited my where-clause to output the correct, depending on the RegType, like this:
WHERE (CASE RegT.Type WHEN 1 THEN TReg.RegistreringsId ELSE DReg.RegistreringsId END = R.Id)

Try putting both tables in the query using LEFT JOIN's
LEFT JOIN TimeRegistration TR ON r.rid = TR.Id AND RegT.type =1
LEFT JOIN DrivingRegistration DR ON r.rid = DR.Id AND RegT.type <>1
Now, in you select clause, use
CASE RegType.Type WHEN 1 THEN TR.SomeField ELSE DR.someField END as SomeField
The other option is to use dynamic SQL

You probably need to perform two left joins, one onto TimeRegistration and one onto DrivingRegistration, and return the fields you want from the appropriate join table something like this:
LEFT JOIN TimeRegistration ON TimeRegistration.RegistreringsId = R.Id
LEFT JOIN DrivingRegistration ON DrivingRegistration.RegistreringsId = R.Id
and you select statement would be something like this:
SELECT CASE WHEN RegT.Type = 1 THEN TimeRegistration.Foo ELSE DrivingRegistration.Bar END
I like what you're trying to do, but I don't think SQL is that clever.

SELECT
R.foo, tr.bar
FROM
SomeTable AS R
INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id
AND RegT1.Type = 1
INNER JOIN TimeRegistration AS tr ON /* whatever */
UNION
SELECT
R.foo, dr.bar
FROM
SomeTable AS R
INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id
AND RegT1.Type = 2
INNER JOIN DrivingRegistration AS dr ON /* whatever */

So I had a scenario where there were three email columns in one table (don't ask why) and any of them could be null (or empty). In this example code I will just deal with a case where it is null.
I had to join it to another table by any of the emails to retrieve the users firstname.
Here is what worked
select
m.email1,
m.email2,
m.email3,
m2.firstName
from MyTable m
left join MyOtherTable m2 on m2.Email =
case when m.email1 is null then
case when m.email2 is null then
case when m.email3 null then
'nonexistent#mydomain.com' -- i stopped here
else m.email3 end
else wm.email2 end
else m.email1 end
Obviously you would include further conditions like
case when m.email1 is null or m.email1 = '' then ...
To cover for empty values.

Related

inner join on multiple conditions when using a database link

Could someone help me figure out why my inner join won't work when I try to use multiple conditions? I'm using a database link to connect my tables, and then using "and" for my second condition. When I only have the first inner join on a.E_id = b.eid it shows results but when I add the second condition it turns up blank...
my code:
select count(*)
from table1#dblink a
inner join table2 b
on a.E_id = b.eid
and a.BUS_ID = b.B_NUMBER
where b.pricing_system = 'M'
;
I have used wildcard character % with like operator. Try below query:
select count(*)
from table1#dblink a
inner join table2 b
on a.E_id = b.eid
and a.BUS_ID like '%'||b.B_NUMBER||'%'
where b.pricing_system = 'M';
If the inner join can't find records with the condition the result will be no rows.
If you want the rows even if the second condition doesn't match, then change it for Left join and change the condition for a Like
And if the 'M' character is in diferents positions of the field, then use the character '%'
You should use this:
select count(*)
from table1#dblink a
Left join table2 b
on a.E_id = b.eid
and a.BUS_ID = b.B_NUMBER
and b.pricing_system = '%M%';

Big Query : LEFT OUTER JOIN cannot be used without a condition that is an equality of fields from both sides of the join

I am writing an equivalent logic in BQ as in my source system. In source SQL server side it is working fine. But in Big query it is failing with the OR condition in the last left outer join condition. If I am moving the OR condition in the where clause it is giving wrong count. Need help to fix this issue. How can I re write the below query ?
SELECT count(*)
FROM stprof PRO
INNER JOIN stdim DIM
ON (DIM.diSet = PRO.diSet)
INNER JOIN DQConfig CFG
ON (CFG.ConSet = PRO.ConSet)
LEFT OUTER JOIN AgSt CCT
ON (CCT.StSet = PRO.StSet)
INNER JOIN stprof SummPRO
ON (SummPRO.diSet = DIM.SummdiSet AND
SummPRO.dIntervalStart = PRO.dIntervalStart AND
SummPRO.SiteId = PRO.SiteId AND
SummPRO.nDuration = PRO.nDuration)
LEFT OUTER JOIN AgSt SummCCT
ON (SummCCT.StSet = SummPRO.StSet)
LEFT OUTER JOIN AgentStatus SummSTS
ON (
SummSTS.StSet = SummPRO.StSet
OR
SummSTS.StSet = PRO.StSet)
WHERE DIM.cType = 'A'
You can replace LEFT JOIN with CROSS JOIN and move condition from ON clause to WHERE clause as in below example
#standardSQL
SELECT COUNT(*)
FROM stprof PRO
INNER JOIN stdim DIM
ON DIM.diSet = PRO.diSet
INNER JOIN DQConfig CFG
ON CFG.ConSet = PRO.ConSet
LEFT OUTER JOIN AgSt CCT
ON CCT.StSet = PRO.StSet
INNER JOIN stprof SummPRO
ON SummPRO.diSet = DIM.SummdiSet
AND SummPRO.dIntervalStart = PRO.dIntervalStart
AND SummPRO.SiteId = PRO.SiteId
AND SummPRO.nDuration = PRO.nDuration
LEFT OUTER JOIN AgSt SummCCT
ON SummCCT.StSet = SummPRO.StSet
CROSS JOIN AgentStatus SummSTS
WHERE DIM.cType = 'A'
AND (
SummSTS.StSet = SummPRO.StSet
OR SummSTS.StSet = PRO.StSet
)

Join on TOP 1 from subquery while referencing outer tables

I am starting with this query, which works fine:
SELECT
C.ContactSys
, ... a bunch of other rows...
FROM Users U
INNER JOIN Contacts C ON U.ContactSys = C.ContactSys
LEFT JOIN UserWatchList UW ON U.UserSys = UW.UserSys
LEFT JOIN Accounts A ON C.AccountSys = A.AccountSys
WHERE
C.OrganizationSys = 1012
AND U.UserTypeSys = 2
AND C.FirstName = 'steve'
Now, I've been given this requirement:
For every visitor returned by the Visitor Search, take ContactSys, get the most recent entry in the GuestLog table for that contact, then return the columns ABC and XYZ from the GuestLog table.
I'm having trouble with that. I need something like this (I think)...
SELECT
C.ContactSys
, GL.ABC
, GL.XYZ
, ... a bunch of other rows...
FROM Users U
INNER JOIN Contacts C ON U.ContactSys = C.ContactSys
LEFT JOIN UserWatchList UW ON U.UserSys = UW.UserSys
LEFT JOIN Accounts A ON C.AccountSys = A.AccountSys
LEFT JOIN (SELECT TOP 1 * FROM GuestLog GU WHERE GU.ContactSys = ????? ORDER BY GuestLogSys DESC) GL ON GL.ContactSys = C.ContactSys
WHERE
C.OrganizationSys = 1012
AND U.UserTypeSys = 2
AND C.FirstName = 'steve'
Only that's not it because that subquery on the JOIN doesn't know anything about the outer tables.
I've been looking at these posts and their answers, but I'm having a hard time translating them to my needs:
SQL: Turn a subquery into a join: How to refer to outside table in nested join where clause?
Reference to outer query in subquery JOIN
Referencing outer query in subquery
Referencing outer query's tables in a subquery
If that is the logic you want, you can use OUTER APPLY:
SELECT C.ContactSys, GL.ABC, GL.XYZ,
... a bunch of other columns ...
FROM Users U JOIN
Contacts C
ON U.ContactSys = C.ContactSys LEFT JOIN
UserWatchList UW
ON U.UserSys = UW.UserSys LEFT JOIN
Accounts A
ON C.AccountSys = A.AccountSys OUTER APPLY
(SELECT TOP 1 gl.*
FROM GuestLog gl
WHERE gl.ContactSys = C.ContactSys
ORDER BY gl.GuestLogSys DESC
) GL
WHERE C.OrganizationSys = 1012 AND
U.UserTypeSys = 2 AND
C.FirstName = 'steve'

Different where conditions through if and else in sql

I am using the following query:
if(#usertype = 'all')
begin
select *
from tbllogin a
left join tblUserType_Master b on a.typeid = b.id
where (b.user_type = 'agent' or b.user_type = 'branch') ;
end
else if(#usertype = 'branch')
begin
select *
from tbllogin a
left join tblUserType_Master b on a.typeid = b.id
where b.user_type = 'branch' ;
end
else if(#usertype = 'agent')
begin
select *
from tbllogin a
left join tblUserType_Master b on a.typeid = b.id
where b.user_type = 'agent' ;
end
This works perfectly fine but the only difference between the three queries is the where condition. Is there any way that I can store the value of where condition in a variable and just add it to the common part.
You already have a variable with the value as far as I can see. Why not simply use it:
select
*
from
tbllogin a
left join tblUserType_Master b on a.typeid=b.id
where
b.user_type = #usertype or (#usertype='all' and b.usertype in ('branch','agent'))
I would also like to point out a couple of things: you are using left joins but comparing to the right-side table, which will eliminate all records from the tbllogin that do not have a match in the tblUserType_Master anyway.
You can do the following instead, it will surely perform better:
select
*
from
tbllogin a
inner join tblUserType_Master b on a.typeid=b.id
where
b.user_type = #usertype or (#usertype='all' and b.usertype in ('branch','agent'))
Also, I strongly recommend against using select *, listing the columns explicitly is a recommended path.
Use CASE Statement in WHERE Clause to get your result :
SELECT * FROM tbllogin a
LEFT OUTER JOIN tblUserType_Master b ON a.typeid=b.id
WHERE ( #usertype='all' AND b.user_type IN ('agent','branch') ) OR
b.user_type = CASE WHEN #usertype='branch' THEN 'branch'
WHEN #usertype='agent' THEN 'agent' END

Inner join on a left join makes the left join behave as a inner join

I have a two lookup tables that I want to inner join on each other, however I only want to left join on my data table.
select * from CLIENT
LEFT JOIN [ENTRY]
on [ENTRY].ENTRY_CODE = CLIENT.CLIENT_COUNTY
and [ENTRY].ENTRY_RECD = 'A'
INNER JOIN [ENTRY_TYPES]
on [ENTRY_TYPES].ENTRY_TYPES_FileRecordID = [ENTRY].ENTRY_TYPE
and [ENTRY_TYPES].ENTRY_TYPES_CODE = 'COUNTY'
and [ENTRY_TYPES].ENTRY_TYPES_RECD = 'A'
where CLIENT_RECD = 'A'
So if ENTRY_TYPES_FileRecordID = ENTRY_TYPE fails I do not want that ENTRY record to be available as a left join item for the join on to CLIENT.
The way the above code is written the left join on ENTRY is behaving like a inner join.
Figured it out on my own as I was typing up the question, I needed to separate out the inner join as a sub-query
select * from CLIENT
left join
(
select ENTRY_CODE, ENTRY_NAME
from [ENTRY]
inner join [ENTRY_TYPES] on ENTRY_TYPES_FileRecordID = ENTRY_TABLE
and ENTRY_TYPES_CODE = 'COUNTY'
and ENTRY_TYPES_RECD = 'A'
where ENTRY_RECD = 'A'
) as CountyLookup on CLIENT_COUNTY = ENTRY_CODE
where CLIENT_RECD = 'A'
You already found a solution yourself, but now you made it a subquery. You can also do this by moving some parts around in your original query and adding two brackets.
So this is just to show an alternative:
SELECT *
FROM [CLIENT]
LEFT JOIN ([ENTRY] --opening bracket
INNER JOIN [ENTRY_TYPES]
ON [ENTRY_TYPES].[ENTRY_TYPES_FileRecordID] = [ENTRY].[ENTRY_TYPE]
AND [ENTRY_TYPES].[ENTRY_TYPES_CODE] = 'COUNTY'
AND [ENTRY_TYPES].[ENTRY_TYPES_RECD] = 'A') -- closing bracket
ON [ENTRY].[ENTRY_CODE] = [CLIENT].[CLIENT_COUNTY]
AND [ENTRY].[ENTRY_RECD] = 'A'
WHERE [CLIENT_RECD] = 'A'