Join under condition in Oracle SQL SELECT statement - sql

I'm trying to join two tables under a condition but I haven't been able to make it work. I've been searching and reading but couldn't find an answer for my case.
This is the basic idea of what I'm trying to achieve (what I wrote in lowercase is what I want to achieve in my own words, in case you wonder):
SELECT TABLE1.STR_FULLNAME, TABLE1.STR_MAILBIZ, TABLE2.STR_IP
FROM TABLE1
INNER JOIN TABLE2
if TABLE2.STR_MACHINEUSER contains 'TEXT\' then join like this:
ON TABLE1.STR_LOGIN = SELECT SUBSTR(STR_MACHINEUSER, 6) AS STR_MACHINEUSER FROM TABLE2 WHERE
STR_MACHINEUSER LIKE 'TEXT\%'
else join like this:
ON TABLE1.STR_LOGIN = TABLE2.STR_MACHINEUSER
ORDER BY TABLE2.DT_INSERT DESC;
The content of Table1.STR_LOGIN and that of Table2.STR_MACHINEUSER are in some cases exactly the same and in some cases a prefix needs to be removed in Table2.STR_MACHINEUSER ('TEXT\'). I've seen that conditions should be handled with the CASE expression. I have tried different ways, but I couldn't make it work for what I need. I'm thinking that I might need a complete different approach, but I don't see what...
Does someone have a suggestion? Thanks in advance!

Maybe this is what you want:
SELECT TABLE1.STR_FULLNAME, TABLE1.STR_MAILBIZ, TABLE2.STR_IP
FROM TABLE1
INNER JOIN TABLE2 ON
(not TABLE2.STR_MACHINEUSER LIKE 'TEXT\%' and TABLE1.STR_LOGIN = TABLE2.STR_MACHINEUSER)
or
(TABLE2.STR_MACHINEUSER LIKE 'TEXT\%' and TABLE1.STR_LOGIN = SUBSTR(TABLE2.STR_MACHINEUSER, 6))
Sure you could shorten your statement using some case construct like:
case
when TABLE2.STR_MACHINEUSER LIKE 'TEXT\%'
then SUBSTR(TABLE2.STR_MACHINEUSER, 6) else TABLE2.STR_MACHINEUSER
end
and compare this to TABLE1.STR_LOGIN but I find (IMHO) the first (logic) join better readable.

Related

Finding differences in queries using two criteria

I'm trying to find a way to find a way to compare two queries that use a combine sent of criteria. In this case we have Prefixes (Two letter code like DA) and Pack number 1234567. In the query I've created a field that combines these two things so it appears 1234567DA this is done with each of the queries from the separate tables they are pulled from. The idea is that if this is in one table and not the other it would show up as "False". I tried to use an Unmatched query but that doesn't seem to work. What I have currently is as follows:
SELECT
[1LagoTest].Prefix,
[1BigPicPackPref].BigPicPP,
IIf([BigPicPP]=[LagoPP],"True","False") AS Compare,
[1LagoTest].RETAIL,
[1LagoTest].MEDIA
FROM 1LagoTest
LEFT JOIN 1BigPicPackPref
ON [1LagoTest].[Prefix] = [1BigPicPackPref].[BigPicPP]
WHERE (((IIf([BigPicPP]=[LagoPP],"True","False")) Like "False")
AND (([1LagoTest].MEDIA) Not Like "*2019 FL*"))
ORDER BY [1LagoTest].RETAIL;
Right now it will show whats missing from LagoPP but doesn't give me anything from missing packs in BigPicPP. Any help in the right direction would be greatly appreciated.
Thanks!!
This gets a little tricky in Access without FULL OUTER JOIN, but the general idea to is replicate a FULL OUTER JOIN using UNION ALL, then filter from that.
Something like this:
SELECT I.Prefix,
I.BigPicPP,
I.Compare,
I.Retail,
I.Media
FROM (SELECT L.Prefix,
B.BigPicPP,
IIf([BigPicPP]=[LagoPP],"True","False") as Compare,
L.Retail,
L.Media
FROM 1LagoTest L
JOIN 1BigPicPackPref B ON L.Prefix = B.BigPicPP
WHERE L.Media NOT LIKE "*2019 FL*"
UNION ALL
SELECT L.Prefix,
B.BigPicPP,
"False", --Missing records from 1BigPicPackPref
L.Retail,
L.Media
FROM 1LagoTest L
LEFT JOIN 1BigPicPackPref B ON L.Prefix = B.BigPicPP
AND L.Media NOT LIKE "*2019 FL*"
WHERE B.Prefix IS NULL
UNION ALL
SELECT B.Prefix,
B.BigPicPP,
"False", --Missing records from 1LagoTest
L.Retail,
L.Media
FROM 1LagoTest L
RIGHT JOIN 1BigPicPackPref B ON L.Prefix = B.BigPicPP
AND L.Media NOT LIKE "*2019 FL*"
WHERE L.Prefix IS NULL
) AS I
You only need IFF in the first part of the union because in the second two parts one side will always be NULL, so we know the compare will always fail and be False.
You shouldn't need this part of your current WHERE clause at all (((IIf([BigPicPP]=[LagoPP],"True","False")) Like "False"). But if you only want to see False records, just add WHERE I.Compare = "False" to the bottom of the outer select.
The reason the "Unmatched" query (assuming through the Wizard) does not work, is because you are attempting to see the values of two separate tables / queries that do not match either table / query. This is not how the "Unmatched" works. All that will give you is a single table / query that does not match another single table / query.
This can most likely be done any number of ways, but this would probably get you where you want to be (or close to it):
SELECT
a.Prefix,
b.BigPicPP,
IIf([BigPicPP]=[LagoPP],"True","False") AS Compare,
a.RETAIL,
a.MEDIA
FROM [1LagoTest] a
LEFT JOIN [1BigPicPackPref] b ON a.Prefix = b.BigPicPP
WHERE a.MEDIA Not Like "*2019 FL*"
AND b.BigPicPP IS NULL
ORDER BY a.RETAIL
UNION
SELECT
a.Prefix,
b.BigPicPP,
IIf([BigPicPP]=[LagoPP],"True","False") AS Compare,
a.RETAIL,
a.MEDIA
FROM [1LagoTest] a
RIGHT JOIN [1BigPicPackPref] b ON a.Prefix = b.BigPicPP
WHERE a.MEDIA Not Like "*2019 FL*"
AND a.Prefix IS NULL
ORDER BY a.RETAIL
NOTE: Depending on the data structure, the ORDER BY may cause some issues.
So the way I got this to finally work was to build two separate queries. One looking at what was missing from Lago and One that was looking at what was missing from BigPic. It was the only way I could get it to give me both sets of missing data. If I can find a better way to do it through one query I will report back as I'm still gonna play around with it.

Case using at Join

I'm trying to use case function at Join and I failed to execute the Query.
What I'm doing wrong?
left join vortex_dbo.vw_public_material_history on
CASE
WHEN vw_public_request_material_location_mir.material_request_id = (substring(vw_public_material_history.comments,12,6))
then vw_public_request_material_location_mir.material_request_id
else null
end
What I wish to get is join rows only if I have "true" from the "When"
I feel I miss something here.
Your CASE expression makes no sense. A CASE expression results in a value, in your case for example in material_request_id. So you'd get
left join vortex_dbo.vw_public_material_history on material_request_id
in case of a string match. You do notice that this ON clause is incomplete?
You are probably looking for
left join vortex_dbo.vw_public_material_history on
vw_public_request_material_location_mir.material_request_id =
(substring(vw_public_material_history.comments,12,6))
That would read better with table aliases:
from vw_public_request_material_location_mir mir
left join vortex_dbo.vw_public_material_history hist on
mir.material_request_id = (substring(hist.comments,12,6))
As to your data model: It seems strange that you have an ID hidden in a string. You may want to re-consider your table design.

How to join YEARS from 2 tables with different format

I am trying to create a custom view in excel for a pivot, I cant join the YEARSF because the tb1 format is 2016-17 and tb2 is 2016/17, how can i join these, see code below... what is the appropriate way of doing this
TB1.YEARF = TB2.YEARF
Seems to be the issue
SELECT TB1.YEARF,
TB1.MC,
TB1.CATEG,
TB1.ID,
TB1.TY,
TB1.CAT,
TB1.LOC,
TB2.HD0_NAME,
TB2.HD1_NAME,
TB2.HD2_NAME,
TB2.HD3_NAME,
TB2.HD4_NAME
FROM DB.TB2 TB2, DB.TB1 TB1
WHERE TB2.CAT = TB1.CAT AND TB2.LOC = TB1.LOC AND TB1.TY = TB2.TY AND TB1.YEARF = TB2.YEARF AND TB1.ID = TB2.ID
It happens that both Oracle and MySQL have REPLACE() functions.
If you change the part of your query that reads
AND TB1.YEARF = TB2.YEARF AND
to
AND TB1.YEARF = REPLACE(TB2.YEARF, '/', '-') AND
you may be able to join these tables. It's not going to be fast.
In general, to do this kind of inexact matching, you have to
figure out the rules for matching. For example, if you want abcd/ef to match abcd-ef then you can use what I wrote above. If you want abcd/ef to match abcd, that's a different rule.
Write a SQL expression to implement your rules.
But, you know, step 1 must come before step 2.
If all you care about is matching the abcd parts of abcd/ef and abcd-ef you can write a rule for that.
AND SUBSTR(TB1.YEARF, 1, 4) = SUBSTR(TB2.YEARF, 1, 4) AND
WHERE Format(TB1.YEARF, "yyyy-dd") = Format(TB2.YEARF, "yyyy-dd")

SQL Join and filter even further

I need to add a condition that only selects the rows where a field (my_galleries.format) equals a string value of 'pictures'. I am trying to add it to this working sql statement.
SELECT
gallery_url,
preview_url
FROM
my_galleries,
my_gallery_previews
WHERE
my_galleries.gallery_id = my_gallery_previews.gallery_id
I tried this, with no luck....
SELECT
gallery_url,
preview_url
FROM
my_galleries,
my_gallery_previews
WHERE
my_galleries.gallery_id = my_gallery_previews.gallery_id
AND my_galleries.format='pictures'
Any ideas?
I recommend not using the FROM foo, bar WHERE foo.key = bar.key approach to performing a JOIN as it isn't very flexible and isn't obvious to new readers of your code. Instead you should perform an explicit JOIN instead:
SELECT
gallery_url,
preview_url
FROM
my_gallery_previews
INNER JOIN my_galleries ON my_gallery_previews.gallery_id = my_galleries.gallery_id
WHERE
my_galleries.format = 'pictures'
How about you try this
SELECT gallery_url, preview_url FROM my_galleries
JOIN my_gallery_previews ON
my_galleries.gallery_id = my_gallery_previews.gallery_id
WHERE my_galleries.format='pictures'
With the join, make sure to prefix your selected columns with their respective tables. I hope this helps
As others have stated I recommend you use the new structure of joining as it is more readable.
SELECT mg.gallery_url,
mgp.preview_url
FROM my_galleries mg
JOIN my_gallery_previews mgp ON mg.gallery_id = mgp.gallery_id
AND mg.format = 'pictures'
You can place the filter condition in the join using an AND statement. (Just another way to do it)
Your query appears to be correct syntax. I would recommend going through your data set or editing it into your question. It is possible that no picture gallery previews currently share a gallery id with an existing gallery row which is stopping the join from functioning.

Oracle SQL - Left join on "in" statements

The point of the query below is to return a list of people and whether or not they are unhappy. But, If I don't know if they are happy or not, I want to list their name and their unhappy as "happy". This is complicated by the fact that I have some additional requirements for what defines unhappy.
I'm writing a query like this...
Select name.firstName,
CASE
WHEN Mood.mood is not null
THEN 'Unhappy'
ELSE 'Happy'
END Unhappy
From name
Mood
WHERE mood.firstName(+) = name.firstName
AND mood.type IN ('Hungry','Tired','Fatigued','Bored',null)
AND mood.value(+) > 5;
So I want to return every single name from the table name, and either a value of "happy" or "unhappy", even though those names may or may not be in mood table. When I run this as I've written it, I get no rows. I figure this might involve my mood.type line because I can't use a left join on an "in" statement.
I think you have a couple of problems:
You have a spurious semi-colon in your WHERE clause.
The CASE expression is in the wrong place.
You shouldn't use NULL in an IN expression.
You could remove the semi-colon and change your IN expression to this instead:
AND (mood.type IN ('Hungry','Tired','Fatigued','Bored') OR mood.type IS NULL)
Also, I'd strongly advise you not to use that obsolete join syntax. It's probably a good idea to use the JOIN keyword as it makes this sort of query a lot easier.
SELECT
name.firstName,
CASE
WHEN Mood.mood IS NOT NULL
THEN 'Unhappy'
ELSE 'Happy'
END Unhappy
FROM name
LEFT JOIN Mood ON
mood.firstName = name.firstName AND
mood.type IN ('Hungry','Tired','Fatigued','Bored') AND
mood.value > 5
I would do it like this:
select n.firstname,
nvl(m.mood, 'Happy') mood
from
name n
left outer join mood m
on n.firstname = m.firstname
where
nvl(m.type,'Hungry') in ('Hungry', 'Tired', 'Fatigued', 'Bored')