Exact last character match in string - sql

My requirement is to match the below characters with the values present in a table column.These characters should be the value in a string.
Characters :
JR
SR
II
III
Table Column values could be :
'MANFORTI JR','KRUMPAK III','PURDY II','MARRONE SR'
if the characters gets matched with the column values then just fetch the
character values and consider it as suffix for the name.
Problem :
The problem is occurring when trying to match II. The value is being fetched
where the column value has III in the string.(Please refer attached screenshot)
Could you please suggest how to do the exact match ?
I come up with the below queries to match the string..
SELECT LAST_NAME A,
CASE WHEN REGEXP_INSTR(LAST_NAME, 'JR$') > 0
THEN SUBSTR(LAST_NAME,REGEXP_INSTR(LAST_NAME, 'JR$'), LENGTH(LAST_NAME))
WHEN REGEXP_INSTR(LAST_NAME, 'SR$') > 0
THEN SUBSTR(LAST_NAME,REGEXP_INSTR(LAST_NAME, 'SR$'), LENGTH(LAST_NAME))
WHEN REGEXP_INSTR(LAST_NAME, 'II$') > 0
THEN SUBSTR(LAST_NAME,REGEXP_INSTR(LAST_NAME, '[II]$'), LENGTH(LAST_NAME))
END SUFFIX
FROM TBL_LAST_NAME
WHERE LAST_NAME IN ('MANFORTI JR','KRUMPAK III','PURDY II','MARRONE SR')
Output :

Prepend a space before the suffix (and you can also use LIKE rather than, more expensive, regular expressions)
SELECT LAST_NAME AS A,
CASE
WHEN LAST_NAME LIKE '% JR'
OR LAST_NAME LIKE '% SR'
OR LAST_NAME LIKE '% II'
THEN SUBSTR(LAST_NAME,-2)
WHEN LAST_NAME LIKE '% III'
THEN SUBSTR(LAST_NAME,-3)
END AS SUFFIX
FROM TBL_LAST_NAME
WHERE LAST_NAME IN ('MANFORTI JR','KRUMPAK III','PURDY II','MARRONE SR')
If you want to use regular expressions then:
SELECT LAST_NAME AS A,
REGEXP_SUBSTR(
last_name,
'\W(SR|JR|II|III)$', -- Match a non-word character then suffix
-- at end-of-string
1, -- Start from the 1st character
1, -- Find the 1st match
'i', -- Case insensitive
1 -- Return the 1st capture group
) AS suffix
FROM TBL_LAST_NAME
WHERE LAST_NAME IN ('MANFORTI JR','KRUMPAK III','PURDY II','MARRONE SR')

Related

How to remove all hyphens and spaces from a string?

I've got the following code:
INSERT INTO DWCUST (DWCUSTID, DWSOURCEIDBRIS, DWSOURCEIDMELB, FIRSTNAME, SURNAME, GENDER, PHONE, POSTCODE, CITY, STATE, CUSTCATNAME)
SELECT dwcustSeq.nextval, cb.custid, Null, cb.fname, cb.sname, UPPER(cb.gender), cb.phone, cb.postcode, cb.city, cb.state, cc.custcatname
FROM a2custbris cb
NATURAL JOIN a2custcategory cc
WHERE cb.rowid IN (SELECT source_rowid FROM A2ERROREVENT where filterid = 5);
I want to adjust it so that before cb.phone (varchar2) values are added to dwcust, all hyphens and spaces are removed from the strings so that they are just numeric.
For instance I want 04-1234 5254 to become 0412345254
Translate can be useful:
translate(cb.phone, 'X- ', 'X')
For example,
select translate(' 04-1234 5254', 'X- ', 'X')
from dual
gives:
TRANSLATE('04-12345254','X-','X')
---------------------------------
0412345254
1 row selected.
About this usage, Oracle docs says:
You cannot use an empty string for to_string to remove all characters
in from_string from the return value. Oracle Database interprets the
empty string as null, and if this function has a null argument, then
it returns null. To remove all characters in from_string, concatenate
another character to the beginning of from_string and specify this
character as the to_string. For example, TRANSLATE(expr,
'x0123456789', 'x') removes all digits from expr.
I would use regexp_replace()
select regexp_replace('04-1234 5254', '[- ]', '')
from dual;
This would still return something that is not a number if it e.g. contains a /
To make sure or to remove everything that is not a number use the following:
select regexp_replace('04-1234 5254', '[^0-9]', '')
from dual;
Just replace cb.phone with regexp_replace(cb.phone, , '[^0-9]', '') in your SELECT list.
SELECT ...., regexp_replace(cb.phone, , '[^0-9]', ''), ....
FROM a2custbris cb
....

Select statement with column contains '%'

I want to select names from a table where the 'name' column contains '%' anywhere in the value. For example, I want to retrieve the name 'Approval for 20 % discount for parts'.
SELECT NAME FROM TABLE WHERE NAME ... ?
You can use like with escape. The default is a backslash in some databases (but not in Oracle), so:
select name
from table
where name like '%\%%' ESCAPE '\'
This is standard, and works in most databases. The Oracle documentation is here.
Of course, you could also use instr():
where instr(name, '%') > 0
One way to do it is using replace with an empty string and checking to see if the difference in length of the original string and modified string is > 0.
select name
from table
where length(name) - length(replace(name,'%','')) > 0
Make life easy on yourselves and just use REGEXP_LIKE( )!
SQL> with tbl(name) as (
select 'ABC' from dual
union
select 'E%FS' from dual
)
select name
from tbl
where regexp_like(name, '%');
NAME
----
E%FS
SQL>
I read the documentation mentioned by Gordon. The relevent sentence is:
An underscore (_) in the pattern matches exactly one character (as opposed to one byte in a multibyte character set) in the value
Here was my test:
select c
from (
select 'a%be' c
from dual) d
where c like '_%'
The value a%be was returned.
While the suggestions of using instr() or length in the other two answers will lead to the correct answer, they will do so slowly. Filtering on function results simply take longer than filtering on fields.

Oracle SQL split column using string functions

In a table(football_team) the values in a column(names) looks like this Andrew Luck , QB . I want to split this column into 3 columns first_name,Last_name,position using PL/SQL functions.
i tried this
select regexp_substr(names,'[^ ,"]+',1,1) as first_name,
regexp_substr(names,'[^ ,"]+',1,2) as last_name,
regexp_substr(names,'[^ ,"]+',1,3) as position from football_team;
doesn't work
Can I make it by using only SUBSTR and INSTR functions.
Please help me. Thanks in advance.
Yes you could use string functions too but IMO regexp is much simpler here. Well as long as you can read regexps, YMMV.
The problem is in regular expressions. Try this instead:
with names(name) as (
select 'Andrew Luck , QB' from dual
union all
select 'John Doe , WB' from dual
)
select
regexp_substr(name, '^([[:alpha:]]+)', 1, 1, '', 1) as firstname
,regexp_substr(name, '^[[:alpha:]]+[[:space:]]+([[:alpha:]]+)', 1, 1, '', 1) as lasttname
,regexp_substr(name, '([[:alpha:]]+)$', 1, 1, '', 1) as position
from names
;
Returns:
FIRSTNAME LASTNAME POSITION
--------- -------- --------
Andrew Luck QB
John Doe WB
The firstname matching regular expressions explained:
^ -- start of the string
( -- start of subexpression group that is referenced by regexp_substr parameter #6 (subexpr)
[ -- start of matching character list
[:alpha:] -- character class expression: alphabet.
] -- end of matching character list
+ -- matches one or more occurrences of the preceding subexpression
) -- end of subexpression group
The explanantion of other two regexps are left as an excercise for the OP.

Oracle SQL - See if Value Contains Substrings from Three Other Values

I have three columns for a person's name (first middle last) and a column for a user ID.
The purpose of this code is to find persons with a UserID that does not match their name.
The UserID is created by taking the FIRST letter of the first name, the FIRST letter of the middle name and the FULL last name. Mary Jane Smith would have the UserID of MJSmith34. Random numbers are added to the end when there is more than one MJSmith, but this does not matter for what I need.
The code below compares the person's last name in two areas. If they do not match, it means that the person's name has been changed. What I need now is to check the UserID against the most current First Middle Last name to see if the UserID need to be changed (updated). The Pseudocode is what I need, but I am not sure if it can even be done. Please help!!
Select DISTINCT
NL.spriden_id as "STU_ID",
NL.SPRIDEN_LAST_NAME as "Last_Name" ,
NL.SPRIDEN_FIRST_NAME as "First_Name"
FROM SARADAP SA
JOIN SPRIDEN NM -- NM is Name
ON SA.SARADAP_PIDM = NM.SPRIDEN_PIDM
JOIN SPRIDEN NL -- NL is null
ON SA.SARADAP_PIDM = NL.SPRIDEN_PIDM
JOIN IDTABLE ID
ON ST.SOMETABLE_PIDM = ID.IDTABLE_PIDM =
WHERE
NM.SPRIDEN_CHANGE_IND LIKE '%N%'
AND
NL.SPRIDEN_CHANGE_IND IS NULL
AND
NL.SPRIDEN_ACTIVITY_DATE between sysdate - 10 and sysdate
AND
NL.spriden_id LIKE 'A00%'
AND
lower(NL.SPRIDEN_LAST_NAME) <> lower(NM.SPRIDEN_LAST_NAME)
AND
NL.SPRIDEN_ACTIVITY_DATE <> NM.SPRIDEN_ACTIVITY_DATE
Pseudocode -
I know I need something with the POSITION of the characters.
I need help making this pseudocode into real code, please! :)
AND ID.USERID LIKE '%(NL.SPRIDEN_LAST_NAME)%'
AND SUBSTRING (1st CHAR OF ID.USERID) LIKE
SUBSTRING FIRST CHARACTER OF (NL.SPRIDEN_FIRST_NAME)
AND SUBSTRING (2nd char of ID.USERID) LIKE
SUBSTRING FIRST CHAR OF (NL.SPRIDEN_MIDDLE_NAME)
AND ID.USERID LIKE SUBSTR(NL.SPRIDEN_FIRST_NAME, 1, 1)
|| SUBSTR(NL.SPRIDEN_MIDDLE_NAME, 1, 1)
|| NL.SPRIDEN_LAST_NAME || '%'
|| is a concatenation operator
This condition means: check if USERID starts with the first symbol SPRIDEN_FIRST_NAME + the first symbol of SPRIDEN_MIDDLE_NAME + SPRIDEN_LAST_NAME
A slight variation on Multisync's good answer:
AND REGEXP_LIKE(ID.USERID, SUBSTR(NL.SPRIDEN_FIRST_NAME, 1, 1)
|| SUBSTR(NL.SPRIDEN_MIDDLE_NAME, 1, 1)
|| NL.SPRIDEN_LAST_NAME || '[0-9]*$', 'i')
-- ^
-- case insensitive compare
That way you won't have false positive for cases such as James Tiberius Kirk => jtkirkwood and you get case insensitive compare "for free".
The drawback here is I assume you don't have regex special characters as part of the name of your users...
Think about normalizing case too!

Select only when the field has more than one word

SELECT name FROM clients;
Table clients
id | name |
1 John
2 John Bravo
3 John Alves
4 Jo
In postgres, how can I select only names with more than one word? For example. This should be the output:
John Bravo
John ALves
I think just test if the name contains a space: where name like '% %'
But this will give you some problem if you name can contain space char befor or after the name, like: ' JOHN' or 'Luck '
If word means to you a space delimited token, then the following would do the trick:
SELECT name FROM clients WHERE name LIKE '% %';
But this will also give you those that have empty names made out of spaces only. Also performance-wise, this will be a costly query.
First you may have to find the number of words in the column, then only select where the number of words is greater than 1.
For example:
SELECT LENGTH(name) - LENGTH(REPLACE(name , ' ', ''))+1 FROM clients;
This will return the number of words in each row, which we have in the field name.
Then you can proceed putting this in a nested select SQL statement something like :
SELECT LENGTH(name) - LENGTH(REPLACE(name, ' ', ''))+1 as mycheck, name FROM clients where (SELECT LENGTH(name) - LENGTH(REPLACE(name, ' ', ''))+1)>1
This will return only where words are greater than 1 (>1). Else you can user >2 to return columns with more than 2 words.
LIKE is an option, or you can use split_part:
SELECT name FROM clients WHERE split_part(trim(name), ' ', 2) <> ''