ORACLE Join tables on a single field and account for minor difference (specific example provided) - sql

I am trying to join two tables on a field (FILE_NAME); however, there are a couple records in just one of the table, in which a timestamp is appended to the end of the file name and before the file extension. I'm not sure how to account for these. I found an Oracle function,
REGEXP SUBSTR (https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions131.htm), that seems like it may give me what I need, but I have to admit that this is extremely advanced to me and am not sure how to apply it.
My sample tables are:
FILE_INFO Table:
FILE_NAME | FILE_ID
REGIONS_ACCOUNTED.xlsx | 21
TSM_INSAT.xml | 14
FILE_PARAMETERS Table:
FILE_NAME
TSM_INSAT.xml
REGIONS_ACCOUNTED-08112017.xlsx
From what I can tell, it seems that the timestamps are always prefixed with a dash (-) so I originally thought to approach it by finding the index of a dash then use substr to concat the before and afters of the timestamp but can't figure out how to do that in a query or how to account for date ranges (e.g.:
REGIONS_ACCOUNTED-07102017-07142017.xlsx
At this point, I just have a basic Join:
SELECT a.file_name, b.file_location
FROM reports.file_info a
LEFT OUTER JOIN reports.file_parameters b on (a.file_name = b.file_name);
The SQL above of course excludes those reports with dates/date ranges in the filename. It would be better to use a file_id, I'm sure; however, there is no file_id in the file_parameters.
Any guidance would be greatly appreciated!

You seem to be looking for match of filenames from FILE_INFO in FILE_PARAMETERS.
SELECT a.file_name,
b.file_location
FROM reports.file_info a
LEFT OUTER JOIN reports.file_parameters b
ON b.file_name LIKE CONCAT('%', SUBSTR(a.file_name, 1, INSTR(a.file_name,'.',-1)-1), '%', SUBSTR(a.file_name, INSTR(a.file_name,'.',-1), LENGTH(a.file_name)), '%');

#Hepc provided the correct answer (in the comments). The modified version to account for date ranges is:
REGEXP_REPLACE(a.file_name,'\-[\d\w\-\_]+.,'.')

Related

Join on phone numbers in different formats

I need an oracle SQL join on two tables on fields with phone numbers that have different formats. The field on one table is the format 555-555-5555 and the other (555) 555-5555.
What is the syntax that could make this work? The tables are small enough I could probably get by with dropping area codes and just focus on the last 4 digits.
Is it possible? If I can't do a join I'm curious of the syntax for a simple compare such as: Where last4(phonenumber) = '4567'
If you want to compare the whole number, you can probably user regexp_replace to keep only the digits and then do the comparison:
where regexp_replace(phone_number,'\D','') = '55555551234';
\D matches non-digit character and removes them.
If last 4 digits will do, you can use substr:
where substr(phone_number,-4) = '1234';
Basically, you can use any string function on your join (in the ON clause, it doesn't have to be straight forward columns, can be calculated values).
For example, following what you suggested, you can use SUBSTR to get the last four digits, and use this on your join:
SELECT * from tableA INNER JOIN tableB on SUBSTR(tableA.num,-4,4) = SUBSTR(tableAB,-4,4)

Trouble getting newest record from grouped records

I'm pretty new to Access so I'm sure this is something simple. I'm not sure I even have the best subject.
I have an Owner and a Names table that contain data like this:
Owner Names
TMKFK NID ... NIDFK Last ModDate
7721011 45 45 Smith 1/18/15
7721011 137 137 Jones 2/1/15
7721012 45 45 Smith 1/18/15
I am trying to query them so that I get the TMKFK for the latest timestamped record in the Name table. This is used for a lookup from a form. So if I lookup Smi* I expect to get 7721012.
After a bunch of looking around on this site and elsewhere and looking at partition over I concluded the answer had to be using a subquery, but I can't quite figure out what to put where. This is where I got stuck:
SELECT Owner.TMKFK
FROM Owner INNER JOIN Names ON Owner.NID = Names.NIDFK
GROUP BY Owner.TMKFK, [Owner Name].Last, [Owner Name].M
WHERE (Owner.TMKFK=7721011 Or Owner.TMKFK=7721012)
AND Names.Last Like "Smith"
AND Names.ModDate=(SELECT Max(Names.ModDate) FROM Names);
This fails because the subquery returns the Max date from the entire table and not just the two records with the same TMKFK. A HAVING clause doesn't seem to make a difference. Re-ordering the fields in group by didn't make a difference.
The subquery to get the max date would need to be restricted to the owner in question. Something along these lines:
SELECT Owner.TMKFK
FROM Owner INNER JOIN Names ON Owner.NID = Names.NIDFK
WHERE (Owner.TMKFK=7721011 Or Owner.TMKFK=7721012)
AND Names.Last Like 'Smith%'
AND Names.ModDate=(SELECT Max(Names.ModDate)
FROM Names
WHERE NIDFK = Owner.NID
)
Don't think you need the GROUP BY. Don't know the Access syntax, but LIKE usually implies wildcards like % and the string should be single quoted. And if you want case-insensitive searching:
AND UPPER(Names.Last) LIKE UPPER('Smith%')

SQL - Left Join - On part of string only

I'm trying to make a Left Join, should be simple enough, I have 2 problems;
The values are in Binary
I need to Join the left 3 characters in one string to the right 3 characters of the other (after they are changed from binary)
Join, Left 3 characters of this one
convert(VARCHAR(max),(file_key7), 102)
in db [RF_Sydney].[dbo].[std_file]
with the Right 3 characters of this one
convert(VARCHAR(max),(code_key), 11)
in db [RF_Sydney].[dbo].[std_code]
In SQL Server, you can join on any condition that can be satisfied; in other words, you can do this:
SELECT *
FROM dbo.std_file f LEFT JOIN std_code c
ON LEFT(convert(VARCHAR(max),(f.file_key7), 102), 3)
= RIGHT(convert(VARCHAR(max),(c.code_key), 11),3)
Performance will suck (unless you use persisted computed columns and define an index).
The best way to do this is to use a computed column in each of those tables. This will allow you to simplify your join code, and even allow you to define an index on the column to improve performance if you need it. As for getting the left and right value, there are LEFT() and RIGHT() functions you can use:
LEFT(convert(VARCHAR(max),(file_key7), 102), 3)
and
RIGHT(convert(VARCHAR(max),(code_key), 11), 3)
For the join expression and query itself, we don't have enough information yet to know exactly how you want these to fit together.
Do you know the length of file_key7 or code_key? Joining LEFT(str,len) = RIGHT(str,len) should work but possible take a big performance hit. Maybe you should create field/column and stick your partial keys in it already converted in the right character format

SQL query to find records with specific prefix

I'm writing SQL queries and getting tripped up by wanting to solve everything with loops instead of set operations. For example, here's two tables (lists, really - one column each); idPrefix is a subset of idFull. I want to select every full ID that has a prefix I'm interested in; that is, every row in idFull which has a corresponding entry in idPrefix.
idPrefix.ID idFull.ID
---------- ----------
12 8
15 12
300 12-1-1
12-1-2
15
15-1
300
Desired result would be everything in idFull except the value 8. Super-easy with a for each loop, but I'm just not conceptualizing it as a set operation. I've tried a few variations on the below; everything seems to return all of one table. I'm not sure if my issue is with how I'm doing joins, or how I'm using LIKE.
SELECT f.ID
FROM idPrefix AS p
JOIN idFull AS f
ON f.ID LIKE (p.ID + '%')
Details:
Values are varchars, prefixes can be any length but do not contain the delimiter '-'.
This question seems similar, but more complex; this one only uses one table.
Answer doesn't need to be fast/optimized/whatever.
Using SQL Server 2008, but am more interested in conceptual understanding than a flavor-specific query.
Aaaaand I'm coming back to both real coding & SO after ~3 years, so sorry if I'm rusty on any etiquette.
Thanks!
You can join the full table to the prefix table with a LIKE
SELECT idFull.ID
FROM idFull full
INNER JOIN idPrefix pre ON full.ID LIKE pre.ID + '%'

SQL trouble with JOIN on INSTR()

I've read lots of examples of JOIN syntax, but none of them work for my problem.
I have a table of quotes and a table of sales enquiries. One quote may result in multiple enquiries, or it may not result in any enquiries. I want to create a list of all quotes and include details of any resulting enquiry. I'm expecting multiple result rows for a quote that resulted in many enquiries. I'm expecting a single row with empty or null enquiries fields, for those quotes that didn't give rise to any enquiries.
The connecting data is in the quotes table, where there's a field called 'activity' that contains the id of any or all enquiries that resulted. It's updated each tim e anew enquiry comes in.
So I tried this:
SELECT q.*, e.id, e.price
FROM quotes as q
LEFT JOIN enquiries as e
ON INSTR(q.activity, e.id) >'0'
WHERE q.date > '2013-07-01'
But every row in my results includes enquiries data. I can't seem to get it to include the quotes that never resulted in anything. I thought LEFT JOIN was supposed to give me all of the quotes regardless of enquiries, and include the enquiries data where there was a match. But every example I've seen is just joining on a.id = b.id, so I suspect that my INSTR() match criteria might be messing things up.
As previous commentators have suggested the issue will be down to the join with Instr. The return value from INSTR of many RDBMSs is an integer value. When you therefore test the value of INSTR against '0' you won't get a match. Also, if Instr doesn't find a match you may get something else returned like MS Access where Null is a possible return value. This is obviously all speculation and we really need to see an example of your data and the issue to confirm if this is the actual problem. In the absence of any more info this is the best you are going to get:
Without knowing which DB you are using I've included a few links for INSTR:
MySql,
Oracle,
MS Access (returns variant Long),
SQL Server - No Instr Function - CharIndex
I think your problem might be somewhere else, because this seems to work fine for me. I assumed the list of enquiries was just a comma separated string. See http://sqlfiddle.com/#!4/71ce1/1
Get rid of the single quotes around the 0, but that doesn't make any difference. Also, you shouldn't be relying on the default date format, but using TO_DATE.You don't say what DBMS you're using, but I tried both Oracle and MySQL.