How to check in SQL which character occurs first in a string - sql

I have a column with string values which I need to parse based on which of the 2 characters occurred first - # and /.
Can you please help me with a SQL select query that will check the string? The possible scenarios are:
Both # and / are present in the string, if so which one comes first
Only 1 of the character occurs in the string

You could use a combination of charindex and outer apply & values, from which you can select the first-occuring character:
select t.*, FirstChar
from t
outer apply(
select top (1) FirstChar
from (values
(CharIndex('#',string),'#'),
(CharIndex('/',string),'/')
)v(i,FirstChar)
where i > 0
order by i
)x;
Demo Fiddle

I wrote this in Oracle before I knew it was MS SQL you needed, maybe it can be of some help anyway?
with data (text) as(
select '#' from dual union all
select '/' from dual union all
select '#/' from dual union all
select '/#' from dual union all
select '/#/' from dual union all
select '//#' from dual union all
select 'aaa#aaa/aaa' from dual union all
select 'aaa/aaa#aaa' from dual union all
select 'aaaaaaaaa' from dual
)
select text ,
case when INSTR(text,'/')=0 and INSTR(text,'#')>0 then '#'
when INSTR(text,'#')=0 and INSTR(text,'/')>0 then '/'
when INSTR(text,'#')>INSTR(text,'/') then '/'
when INSTR(text,'#')<INSTR(text,'/') then '#'
else ' '
end first from data;

Related

Oracle db - remove ,, from email address

I'm running below code and getting below results but I want to remove ,, and after ,, texts from email address and that email address should show in UPPER(PT_PARTNER_EMAIL) VALID_EMAIL_ID column.
How can I achieve this?
select party_id, pt_partner_id, pt_partner_email, upper(pt_partner_email) valid_email_id
from odi_ods_partner_dim
where length(pt_partner_email) > 3
PARTY_ID PT_PARTNER_ID PT_PARTNER_EMAIL VALID_EMAIL_ID
3223218102E17 10101363 DEEPAKSKORI#GMAIL.COM,,ALL DEEPAKSKORI#GMAIL.COM,,ALL
5951118102E17 12059043 jalaj79#gmail.com,, JALAJ79#GMAIL.COM,,
1113418102E17 12059044 hassanselim1993#gmail.com,, HASSANSELIM1993#GMAIL.COM,,
2579321752017 36419244 drshetty#surgicare.co.in,, DRSHETTY#SURGICARE.CO.IN,,
please suggest how can I achive this.
try using these
Upper - Make all to upper case
https://www.techonthenet.com/oracle/functions/upper.php
Instr - find the position of ,,
https://www.techonthenet.com/oracle/functions/instr.php
Substr - Cut from start to where ,, is
https://www.techonthenet.com/oracle/functions/substr.php
e.g.
select upper( substr('wo++' , 1 , instr('wo++' , '++' )-1 ) ) from dual
--result WO
You can check if the ,, substring exists using the INSTR function and then, if it does, remove it using SUBSTR and INSTR:
SELECT party_id,
pt_partner_id,
pt_partner_email,
UPPER(
CASE INSTR(pt_partner_email, ',,')
WHEN 0
THEN pt_partner_email
ELSE SUBSTR(pt_partner_email, 1, INSTR(pt_partner_email, ',,') - 1)
END
) AS valid_email_id
FROM odi_ods_partner_dim
WHERE LENGTH(pt_partner_email) > 3
Which, for the sample data:
CREATE TABLE odi_ods_partner_dim (PARTY_ID, PT_PARTNER_ID, PT_PARTNER_EMAIL) AS
SELECT '3223218102E17', 10101363, 'DEEPAKSKORI#EXAMPLE.COM,,ALL' FROM DUAL UNION ALL
SELECT '5951118102E17', 12059043, 'jalaj79#example.com,,' FROM DUAL UNION ALL
SELECT '1113418102E17', 12059044, 'hassanselim1993#example.com,,' FROM DUAL UNION ALL
SELECT '2579321752017', 36419244, 'drshetty#example.co.in,,' FROM DUAL UNION ALL
SELECT 'ABC1234567890', 12345678, 'example#example.com' FROM DUAL;
Note: this includes an extra rows which does not contain ,,.
Outputs:
PARTY_ID
PT_PARTNER_ID
PT_PARTNER_EMAIL
VALID_EMAIL_ID
3223218102E17
10101363
DEEPAKSKORI#EXAMPLE.COM,,ALL
DEEPAKSKORI#EXAMPLE.COM
5951118102E17
12059043
jalaj79#example.com,,
JALAJ79#EXAMPLE.COM
1113418102E17
12059044
hassanselim1993#example.com,,
HASSANSELIM1993#EXAMPLE.COM
2579321752017
36419244
drshetty#example.co.in,,
DRSHETTY#EXAMPLE.CO.IN
ABC1234567890
12345678
example#example.com
EXAMPLE#EXAMPLE.COM
db<>fiddle here
Here is one option:
with test1 as(
select 'DEEPAKSKORI#GMAIL.COM,,ALL' VALID_EMAIL_ID from dual union all
select 'jalaj79#gmail.com,,' VALID_EMAIL_ID from dual union all
select 'hassanselim1993#gmail.com,,' VALID_EMAIL_ID from dual union all
select 'drshetty#surgicare.co.in,,' VALID_EMAIL_ID from dual
)
select upper(substr(VALID_EMAIL_ID,1,instr(VALID_EMAIL_ID,',,')-1)) from test1
Result:
DEEPAKSKORI#GMAIL.COM
JALAJ79#GMAIL.COM
HASSANSELIM1993#GMAIL.COM
DRSHETTY#SURGICARE.CO.IN

Find value that is not a number or a predefined string

I have to test a column of a sql table for invalid values and for NULL.
Valid values are: Any number and the string 'n.v.' (with and without the dots and in every possible combination as listed in my sql command)
So far, I've tried this:
select count(*)
from table1
where column1 is null
or not REGEXP_LIKE(column1, '^[0-9,nv,Nv,nV,NV,n.v,N.v,n.V,N.V]+$');
The regular expression also matches the single character values 'n','N','v','V' (with and without a following dot). This shouldn't be the case, because I only want the exact character combinations as written in the sql command to be matched. I guess the problem has to do with using REGEXP_LIKE. Any ideas?
I guess this regexp will work:
NOT REGEXP_LIKE(column1, '^([0-9]+|n\.?v\.?)$', 'i')
Note that , is not a separator, . means any character, \. means the dot character itself and 'i' flag could be used to ignore case instead of hard coding all combinations of upper and lower case characters.
No need to use regexp (performance will increase by large data) - plain old TRANSLATE is good enough for your validation.
Note that the first translate(column1,'x0123456789','x') remove all numeric charcters from the string, so if you end with nullthe string is OK.
The second translate(lower(column1),'x.','x') removes all dots from the lowered string so you expect the result nv.
To avoid cases as n.....v.... you also limit the string length.
select
column1,
case when
translate(column1,'x0123456789','x') is null or /* numeric string */
translate(lower(column1),'x.','x') = 'nv' and length(column1) <= 4 then 'OK'
end as status
from table1
COLUMN1 STATUS
--------- ------
1010101 OK
1012828n
1012828nv
n.....v....
n.V OK
Test data
create table table1 as
select '1010101' column1 from dual union all -- OK numbers
select '1012828n' from dual union all -- invalid
select '1012828nv' from dual union all -- invalid
select 'n.....v....' from dual union all -- invalid
select 'n.V' from dual; -- OK nv
You can use:
select count(*)
from table1
WHERE TRANSLATE(column1, ' 0123456789', ' ') IS NULL
OR LOWER(column1) IN ('nv', 'n.v', 'nv.', 'n.v.');
Which, for the sample data:
CREATE TABLE table1 (column1) AS
SELECT '12345' FROM DUAL UNION ALL
SELECT 'nv' FROM DUAL UNION ALL
SELECT 'NV' FROM DUAL UNION ALL
SELECT 'nV' FROM DUAL UNION ALL
SELECT 'n.V.' FROM DUAL UNION ALL
SELECT '...................n.V.....................' FROM DUAL UNION ALL
SELECT '..nV' FROM DUAL UNION ALL
SELECT 'n..V' FROM DUAL UNION ALL
SELECT 'nV..' FROM DUAL UNION ALL
SELECT 'xyz' FROM DUAL UNION ALL
SELECT '123nv' FROM DUAL;
Outputs:
COUNT(*)
5
or, if you want any quantity of . then:
select count(*)
from table1
WHERE TRANSLATE(column1, ' 0123456789', ' ') IS NULL
OR REPLACE(LOWER(column1), '.') = 'nv';
Which outputs:
COUNT(*)
9
db<>fiddle here

How to cut everything after a specific character, but in case string doesn't contain it do nothing?

Let's say i have following data:
fjflka, kdjf
ssssllkjf fkdsjl
skfjjsld, kjl
jdkfjlj, ksd
lkjlkj hjk
I want to cut out everything after ',' but in case the string doesn't contain this character, it wont do anything, if i use substr and cut everything after ',' the string which doesn't contain this character shows as null. How do i achieve this? Im using oracle 11g.
This should work. Simply use regexp_substr
with t_view as (
select 'fjflka, kdjf' as text from dual union
select 'ssssllkjf fkdsjl' from dual union
select 'skfjjsld, kjl' from dual union
select 'jdkfjlj, ksd' from dual union
select 'lkjlkj hjk' from dual
)
select text,regexp_substr(text,'[^,]+',1,1) from t_view;
Assuming your table :
SQL> desc mytable
s varchar2(100)
you may use:
select decode(instr(s,','),0,s,substr(s,1,instr(s,',')-1)) from mytable;
demo
Well the below query works as per your requirement.
with mytable as
(select 'aaasfasf wqwe' s from dual
union all
select 'aaasfasf, wqwe' s from dual)
select s,substr(s||',',1,instr(s||',',',')-1) from mytable;

How to add a space to an existing string in Oracle character functions without using regular expressions

I have a field as name in a table with names inserted without spaces. Eg: "MarkJones".
Now I want to create a space between the first and lastname of a person within the same column to be displayed as "Mark Jones" using Oracle functions.
I have tried this query
SELECT instr('MarkJones', '%||Upper(*)||%') AS substr1,
SUBSTR('MarkJones', instr('MarkJones', '%lower(*)upper(*)%')) AS substr2,
substr1||' '||substr2
FROM dual
;
However, this query is not working. I want to try it using oracle functions including translate, substr and instr, but no regular expressions.
This approach works for the simple example given, but fails if the name has more than 2 uppercase letters in it. If this is coursework as expected, maybe the requirements are not too difficult for the names to parse as we all know that is fraught with heartache and you can never account for 100% of names from all nationalities.
Anyway my approach was to move through the string looking for uppercase letters and if found replace them with a space followed by the letter. I used the ASCII function to test their ascii value to see if they were an uppercase character. The CONNECT BY construct (needed to loop through each character of the string) returns each character in its own row so LISTAGG() was employed to reassemble back into a string and ltrim to remove the leading space.
I suspect if this is coursework it may be using some features you should not be using yet. At least you should get out of this the importance of receiving and/or giving complete specifications!
SQL> with tbl(name) as (
select 'MarkJones' from dual
)
select ltrim(listagg(case
when ascii(substr(name, level, 1)) >= 65 AND
ascii(substr(name, level, 1)) <= 90 THEN
' ' || substr(name, level, 1)
else substr(name, level, 1)
end, '')
within group (order by level)) fixed
from tbl
connect by level <= length(name);
FIXED
------------------------------------
Mark Jones
When you are ready, here's the regexp_replace version anyway :-)
Find and "remember" the 2nd occurrence of an uppercase character then replace it with a space and the "remembered" uppercase character.
SQL> with tbl(name) as (
select 'MarkJones' from dual
)
select regexp_replace(name, '([A-Z])', ' \1', 1, 2) fixed
from tbl;
FIXED
----------
Mark Jones
Not sure we should go against #Alex Poole advice, but it looks like an homework assignment.
So my idea is to point the second Upper Case. Its doable if you create a set of the upper cases, on which you valuate the position in input string iStr. Then if you're allowed to use length, you can use this position to build firstName too:
SELECT substr(iStr, 1, length(iStr)-length(substr(iStr, instr(iStr, u)))) firstName
, substr(iStr, instr(iStr, u)) lastName
, substr(iStr, 1, length(iStr)-length(substr(iStr, instr(iStr, u)))) ||' '||
substr(iStr, instr(iStr, u)) BINGO
FROM ( select 'MarkJones' iStr from dual
union all select 'SomeOtherNames' from dual -- 2 u-cases gives 2 different results
union all select 'SomeOtherOols' from dual -- only one result
union all select 'AndJim' from dual
union all select 'JohnLenon' from dual
union all select 'LemingWay' from dual
),
( select 'A' U from dual
union all select 'B' from dual
union all select 'C' from dual
union all select 'D' from dual
union all select 'E' from dual
union all select 'F' from dual
union all select 'G' from dual
union all select 'H' from dual
union all select 'I' from dual
union all select 'J' from dual
union all select 'K' from dual
union all select 'L' from dual
union all select 'M' from dual
union all select 'N' from dual
union all select 'O' from dual
union all select 'P' from dual
union all select 'Q' from dual
union all select 'R' from dual
union all select 'S' from dual
union all select 'T' from dual
union all select 'U' from dual
union all select 'V' from dual
union all select 'W' from dual
union all select 'X' from dual
union all select 'Y' from dual
union all select 'Z' from dual
) upper_cases
where instr(iStr, U) > 1
;

how to select exact 7 or 10 world in oracle using regular expression

I am working on below query, I am expected to select exact 7 or 10 digit values columns using regular expression, I have used express in regexp_like() function of oracle, but its not working, please help
Query :
select * from
(select '1234567CELL' "a" from dual
union
select '123CaLLAsasd12' "a" from dual
union
select 'as9960488188CELLas12' "a" from dual
union
select '1234567' "a" from dual
union
select '9960488188' "a" from dual
union
select 'asdCELLqw' "a" from dual) b
where b."a" like '%CELL%' and regexp_like(b."a",'^(\d{7}|\d{10})$');
Expected output
"1234567"
"9960488188"
as above two rows, please check
^ and $ match the start and end of a string and the value cannot contain the string CELL and be solely a 7- or 10-digit number. Instead you could use the regular expression (^|\D)(\d{7}|\d{10})($|\D) which will match either the start of the string or a not digit character (^|\D) then either 7- or 10- digits and then either the end of the string or a non digit character ($|\D).
Like this:
WITH data ( a ) AS (
select '1234567CELL' from dual union
select '123CaLLAsasd12' from dual union
select 'as9960488188CELLas12' from dual union
select '1234567' from dual union
select '9960488188' from dual union
select 'asdCELLqw' from dual
)
SELECT a,
REGEXP_SUBSTR( a, '(^|\D)(\d{7}|\d{10})($|\D)', 1, 1, NULL, 2 ) AS val
FROM data
WHERE a LIKE '%CELL%'
AND REGEXP_LIKE( a, '(^|\D)(\d{7}|\d{10})($|\D)');
Output:
A VAL
-------------------- ----------
1234567CELL 1234567
as9960488188CELLas12 9960488188
You may just use
where regexp_like(b."a",'^([[:digit:]]{7}|[[:digit:]]{10})$')
Since the pattern is anchored (^ matches the start of the string and $ matches the end of the string) there can't be CELL inside the entries you fetch, and you can remove where b."a" like '%CELL%' from the query.