Trim string after first occurrence of a character - sql

I'm working with a varchar column in AWS Redshift. Each string in it has at least one hyphen (-).
I want to keep the substring after the first hyphen. For example:
00-11-22-33 -> 11-22-33
00-112233 -> 112233
The solutions to this question do not work when there are multiple hyphens in a string.
For instance:
select
split_part('00-11-22-33', '-', 2) as attempt1 -- returns '11'
, regexp_replace( '00-11-22-33', '.*-', '') as attempt2 -- returns '33'
;
I'm looking for a solution that returns 11-22-33.

If there's always a hyphen, and you always want only what is after the first hyphen, you may be working too hard.
Here's a more brute force approach.
select substring(
'00-11-22-33'
FROM charindex('-', '00-11-22-33') + 1)
)
or
select substring(
'00-11-22-33',
charindex('-', '00-11-22-33') + 1,
len('00-11-22-33') - charindex('-', '00-11-22-33')
)
or
select substring(
'00-11-22-33',
charindex('-', '00-11-22-33') + 1,
len('00-11-22-33')
)
...because it won't return more characters than exist.

You could match until the first hyphen with ^[^-]*-
And replace with an empty string.
regexp_replace('00-11-22-33', '^[^-]*-', '');
If there should be at least a single char after the hyphen, then you can match with this pattern and replace with capture group 1 like '$1' instead of an empty string.
^[^-]*-(.+)
If the char after the hyphen should not be another hyphen, then you can match a single char other than a hyphen and also replace with '$1'
^[^-]*-([^-].*)

Related

SQL How to extract Middle Characters in a string

I have a string that looks like this. I need to extract after the third '/', or to pull out the section called 'Reports' from this string.
/WM/Operational/Reports/ReportName
I have tried the following:
This gives me the last part or the ReportName
= RIGHT(col,charindex('/',reverse(col),1)-1)
this removes the leading characters after the 3rd '/' character (number of characters are different than above string to hide details)
= RIGHT(col, LEN(col) - 31)
How do I combine this together to remove the first part after the 3rd '/' and remove the reportname?
Assuming the format of your example string has no more than 4 parts you could make use of parsename here:
declare #col varchar(50) = '/WM/Operational/Reports/ReportName';
select ParseName(Replace(stuff(#col, 1, 1, ''), '/', '.'), 2);

why output is null at select translate(' #',' ','') from dual; and why resulit is # at select replace(' #',' ','') from dual;

Basically translate will change character to character and Replace string to string , and here i have tried to remove spaces using translate to count the number words .
select translate(' #',' ','') from dual;
select replace(' #',' ','') from dual;
select ename , nvl(length(replace(TRANSLATE(upper(trim(ename)),'ABCDEFGHIJKLMNOPQRSTUVWXYZ'' ',' # '),' ',''))+1,1) NOOFWORDs
from emp;
Unfortunately Oracle has made many bizarre choices around null vs. empty string.
One of those has to do with TRANSLATE. TRANSLATE will return NULL if any of its arguments (including the last one) is NULL, no matter what the logical behavior should be.
So, to remove spaces (say) with TRANSLATE, you must add a character you do NOT want to be removed to both the second and the third argument. I added the lower-case letter z, but you could add anything (a dot, the digit 0, whatever - just make sure you add the same character at the beginning of both arguments)
... translate (input_string, 'z ', 'z') ....
For example:
select translate(' #','z ','z') from dual;
TRANSLATE('#','Z','Z')
------------------------
#
select translate(' #',' ','') from dual;
Returns NULL because in Oracle empty strings unfortunately yield NULLs. Therefore it's equivalent to
SELECT translate(' #', ' ', NULL)
FROM dual;
and translate() returns NULL when an argument is null. Actually this is well documented in "TRANSLATE":
(...)
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.
If you want to replace one character, use replace() as you already did. For a few but more than one characters you can nest the replace()s.
This however gets unhandy, when you want to replace quite a lot of characters. In such a situation, if the replacement character is only one character or the empty string regexp_replace() using a character class or alternates may come in handy.
For example
SELECT regexp_replace('a12b478c01', '[0-9]', '')
FROM dual;
replaces all the digits so just 'abc' remains and
SELECT regexp_replace('ABcc1233', 'c|3', '')
FROM dual;
removes any '3' or 'c' and results in 'AB12'. In your very example
SELECT regexp_replace(' #', ' ', '')
FROM dual;
would also work and give you '#'. Though in the simple case of your example a simple replace() is enough.

Replace function combined with ltrim and rtrim

Can someone please help me to understand the following code:
REPLACE(LTRIM(RTRIM(dbo.UFN_SEPARATES_COLUMNS(CompletionDetails, 3, ','))), '.', '') AS BuildRequestID,
Does it say remove all trailing and leading spaces, then replace 3 with comma. Next, if there is ., replace it with ' '?
It does not at any point replace 3 with ,.
We can make all this easier to follow by formatting the full expression to cover multiple lines:
REPLACE(
LTRIM(RTRIM(
dbo.UFN_SEPARATES_COLUMNS(CompletionDetails, 3, ',')
))
,'.', ''
) AS BuildRequestID,
Expressions like this have to read from the inside out. So we start with this inner-most part:
dbo.UFN_SEPARATES_COLUMNS(CompletionDetails, 3, ',')
This UFN_SEPARATES_COLUMNS() function is not part of Sql Server, but was added by someone at your organization or as part of the vendor software package for the database you're looking at. But I'm confident based on inferences and the link (found via Google) it will treat CompletionDetails as delimited text, where the delimiter is a comma (based on the 3rd ',' argument) and returns the 3rd field (based on the 2nd 3 argument, where counting starts at 1 rather than 0). As CSV parsers go, this one is particularly naive, so be very careful what you expect from it.
Then we use LTRIM() and RTRIM() to remove both leading and trailing blanks from the field. Not all whitepsace is removed; only space characters. Tabs, line feeds, etc are not trimmed. Sql Server 2017 has a new TRIM() function that can handle wider character sets and do both sides of the string with one call.
The code then uses the REPLACE() function to remove all . characters from the result (replaces them with an empty string).
The code is trimming the leading and trailing spaces via the LTRIM() and RTRIM() functions of whatever is returned from the function dbo.x_COLUMNS... i.e. dbo.x_COLUMNS(CompletionDetails, 3, ','). LTRIM is left, RTRIM is right.
It then is replacing all periods (.) with nothing via the REPLACE() function.
So in summary, it's removing all periods from the string and the leading and trailing spaces.
The LTRIM removes leading spaces. RTRIM removes trailing spaces. REPLACE removes the period.
Declare #Val Char(20) = ' Frid.ay '
Select REPLACE(
LTRIM(
RTRIM(
#Val --dbo.x_COLUMNS(CompletionDetails, 3, ',')
)
), '.', ''
)
Result
BuildRequestID
--------------
Friday
remove all trailing and leading spaces, then replace 3 with comma.
Next, if there is ., replace it with ' '
No it does not say that.
But this does:
REPLACE(REPLACE(LTRIM(RTRIM(CompletionDetails)), '3', ','), '.', ' ')
it's not clear if you want . replaced by ' ' or ''.
I used the 1st case, you can change it as you like.
It's easier to understand like this:
remove all trailing and leading spaces: LTRIM(RTRIM(CompletionDetails))
replace 3 with comma: REPLACE( ?, '3', ',')
replace it with ' ': REPLACE(? , '.', ' ') or REPLACE(? , '.', '')

SQL: how to select a substring between special characters

My string looks something like this:
\\\abcde\fghijl\akjfljadf\\
\\xyz\123
I want to select everything between the 1st set and next set of slashes
Desired result:
abcde
xyz
EDITED: To clarify, the special character is always slashes - but the leading characters are not constant, sometimes there are 3 slashes and other times there are only 2 slashes, followed by texts, and then followed by 1 or more slashes, some more texts, 1 or more slash, so on and so forth. I'm not using any adapter at all, just looking for a way to select this substring in my SQL query
Please advise.
Thanks in advance.
You could do a cross join to find the second position of the backslash. And then, use substring function to get the string between 2nd and 3rd backslash of the text like this:
SELECT substring(string, 3, (P2.Pos - 2)) AS new_string
FROM strings
CROSS APPLY (
SELECT (charindex('\', replace(string, '\\', '\')))
) AS P1(Pos)
CROSS APPLY (
SELECT (charindex('\', replace(string, '\\', '\'), P1.Pos + 1))
) AS P2(Pos)
SQL Fiddle Demo
UPDATE
In case, when you have unknown number of backslashes in your string, you could just do something like this:
DECLARE #string VARCHAR(255) = '\\\abcde\fghijl\akjfljadf\\'
SELECT left(ltrim(replace(#string, '\', ' ')),
charindex(' ',ltrim(replace(#string, '\', ' ')))-1) AS new_string
SQL Fiddle Demo2
Use substring, like this (only works for the specified pattern of two slashes, characters, then another slash):
declare #str varchar(100) = '\\abcde\cc\xxx'
select substring(#str, 3, charindex('\', #str, 3) - 3)
Replace #str with the column you actually want to search, of course.
The charindex returns the location of the first slash, starting from the 3rd character (i.e. skipping the first two slashes). Then the substring returns the part of your string starting from the 3rd character (again, skipping the first two slashes), and continuing until just before the next slash, as determined by charindex.
Edit: To make this work with different numbers of slashes at the beginning, use patindex with regex to find the first alphanumeric character, instead of hardcoding that it should be the third character. Example:
declare #str varchar(100) = '\\\1Abcde\cc\xxx'
select substring(#str, patindex('%[a-zA-Z0-9]%', #str), charindex('\', #str, patindex('%[a-zA-Z0-9]%', #str)) - patindex('%[a-zA-Z0-9]%', #str))
APH's solution works better if your string always follows the pattern as described. However this will get the text despite the pattern.
declare #str varchar(100) = '\\abcde\fghijl\akjfljadf\\'
declare #srch char(1) = '\'
select
SUBSTRING(#str,
(CHARINDEX(#srch,#str,(CHARINDEX(#srch,#str,1)+1))+1),
CHARINDEX(#srch,#str,(CHARINDEX(#srch,#str,(CHARINDEX(#srch,#str,1)+1))+1))
- (CHARINDEX(#srch,#str,(CHARINDEX(#srch,#str,1)+1))+1)
)
Sorry for the formatting.
Edited to correct user paste error. :)

Replace everything after second occurrence with blank

I have a string a/b/c I want to replace everything after second occurrence of "/" to blank so my result should like this a/b
any help will be appreciated.
Here what i tired nothing is working
select reverse(left(reverse('a/b/c'), charindex('/', reverse('a/b/c')) -1))
SELECT SUBSTRING('a/b/c', 1, LEN('a/b/c') )
SELECT STUFF('a/b/c', charindex('/', 'a/b/c'), 2, '');
select CHARINDEX('/','a/b/c')
select right ('a/b/c', CHARINDEX('/','a/b/c')-1)
You can use:
SELECT LEFT('a/b/c',CHARINDEX('/','a/b/c',CHARINDEX('/','a/b/c')+1)-1)
The optional third parameter of CHARINDEX is the starting position, ie where in the string it should start looking for the desired character, by nesting another CHARINDEX function as the third parameter you can find the 2nd occurrence. The +1 is so it doesn't find the same '/' in the nested CHARINDEX, the -1 is so it doesn't return the 2nd '/' as part of your result.
You can use the following:
select stuff('ashish jain',charindex('a','ashish jain',charindex('a','ashish jain')+1),1,'c')
It will replace 'a' with 'c' and return 'ashish jcin'.
Replace rest of all occurrence characters except first occurrence.
declare #word varchar(500)='B-123, Address1-Address2-Address3'
select CONCAT_WS('',left(#word,CHARINDEX('-',#word)), replace( substring(#word,CHARINDEX('-',#word)+1, len(#word)),'-',' '))