SQL Server - remove left part of string before a specific character - sql-server

I have a VARCHAR value that looks like this:
5.95 $ Additional fees
How can I remove everything left from character '$' (including that character) ? So that I get the following result:
Additional fees
The '$' is always present.

STUFF and CHARINDEX would be the simpliest way, in my opinion:
SELECT STUFF(YourColumn,1, CHARINDEX('$',YourColumn),'')
FROM (VALUES('5.95 $ Additional fees'))V(YourColumn);
Note that as $ has a whitespace afterwards, the value returned will have a leading whitespace (' Additional fees'). You could use TRIM (or LTRIM and RTRIM on older versions of SQL Server) to remove this, if it isn't wanted.
I haven't assumed that the portion string to be replaced is CHARINDEX('$',YourColumn)+1, as we have one sample. As far as we know, you could also have values such as '10.99$Base Cost'. If the +1 was used, it would return 'ase Cost' for such a value.

Hello do it like below syntax
declare #temp nvarchar(max)='5.95 $ Additional fees'
select SUBSTRING(#temp,charindex('$',#temp)+1,len(#temp)-1)

You can use SUBSTRING get the particular string and CHARINDEX function to get index of special character, in your case $.
DECLARE #Var VARCHAR(100)
SET #Var = '5.95 $ Additional fees'
SELECT SUBSTRING(#Var, CHARINDEX('$', #Var) + 1, LEN(#Var) - LEN(LEFT(#Var, CHARINDEX('$', #Var))))

Related

Is there a way to find values that contain only 0's and a symbol of any length?

I want to find strings of any length that contain only 0's and a symbol such as a / a . or a -
Examples include 0__0 and 000/00/00000 and .00000
Considering this sample data:
CREATE TABLE dbo.things(thing varchar(255));
INSERT dbo.things(thing) VALUES
('0__0'),('000/00/00000'),('00000'),('0123456');
Try the following, which locates the first position of any character that is NOT a 0, a decimal, a forward slash, or an underscore. PATINDEX returns 0 if the pattern is not found.
SELECT thing FROM dbo.things
WHERE PATINDEX('%[^0^.^/^_]%', thing) = 0;
Results:
thing
0__0
000/00/00000
00000
The opposite:
SELECT thing FROM dbo.things
WHERE PATINDEX('%[^0^.^/^_]%', thing) > 0;
Results:
thing
0123food456
Example db<>fiddle
I can see a way of doing this... But it's something that wouldn't perform well, if you think about using it as a search criteria.
We are going to use a translate function on SQL Server, to replace the allowed characters, or symbols as you've said, with a zero. And then, eliminates the zeroes. If the result is an empty string, then there are two cases, or it only had zeroes and allowed characters, or it already was an empty string.
So, checking for this and for non-empty strings, we can define if it matches your criteria.
-- Test scenario
create table #example (something varchar(200) )
insert into #example(something) values
--Example cases from Stack Overflow
('0__0'),('000/00/00000'),('.00000'),
-- With something not allowed (don't know, just put a number)
('1230__0'),('000/04560/00000'),('.00000789'),
-- Just not allowed characters, zero, blank, and NULL
('1234567489'),('0'), (''),(null)
-- Shows the data, with a column to check if it matches your criteria
select *
from #example e
cross apply (
select case when
-- If it *must* have at least a zero
e.something like '%0%' and
-- Eliminates zeroes
replace(
-- Replaces the allowed characters with zero
translate(
e.something
,'_./'
,'000'
)
,'0'
,''
) = ''
then cast(1 as bit)
else cast(0 as bit)
end as doesItMatch
) as criteria(doesItMatch)
I really discourage you from using this as a search criteria.
-- Queries the table over this criteria.
-- This is going to compute over your entire table, so it can get very CPU intensive
select *
from #example e
where
-- If it *must* have at least a zero
e.something like '%0%' and
-- Eliminates zeroes
replace(
-- Replaces the allowed characters with zero
translate(
e.something
,'_./'
,'000'
)
,'0'
,''
) = ''
If you must use this as a search criteria, and this will be a common filter on your application, I suggest you create a new bit column, to flag if it matches this, and index it. Thus, the increase in computational effort would be spread on the inserts/updates/deletes, and the search queries won't overloading the database.
The code can be seen executing here, on DB Fiddle.
What I got from the question is that the strings must contain both 0 and any combination of the special characters in the string.
If you have SQL Server 2017 and above, you can use translate() to replace multiple characters with a space and compare this with the empty string. Also you can use LIKE to enforce that both a 0 and any combination of the special character(s) appear at least once:
DECLARE #temp TABLE (val varchar(100))
INSERT INTO #temp VALUES
('0__0'), ('000/00/00000'), ('.00000'), ('w0hee/'), ('./')
SELECT *
FROM #temp
WHERE val LIKE '%0%' --must have at least one zero somewhere
AND val LIKE '%[_/.]%' --must have at least one special character(s) somewhere
AND TRANSLATE(val, '0./_', ' ') = '' --translated zeros and sp characters to spaces equivalent to an empty string
Creates output:
val
0__0
000/00/00000
.00000

does LEN() have bug?

It seems that LEN() ignores whitespaces at the right side of a variable.
declare #a varchar(100)
set #a = 'John '
print len(#a)
The above code prints 4 whereas it should be 7.
Is this a bug?
This is not a bug, this is the intended behavior. To quote the documentation:
LEN excludes trailing spaces. If that is a problem, consider using the DATALENGTH (Transact-SQL) function which does not trim the string
Not a bug, is right there in the documentation:
Returns the number of characters of the specified string expression, excluding trailing spaces.
Please read the official documentation. It is expected behaviour. https://learn.microsoft.com/en-us/sql/t-sql/functions/len-transact-sql?view=sql-server-ver15#remarks
Thank you folks,
I really didn't know that LEN() ignores trailing spaces!
I think DATALENGTH() does not return a correct answer always.
For NVARCHAR() type it returns twice the number of characters in a string. In fact, it returns the total number of bytes that the string consumes in memory.
In my opinion in order to get the correct length of a string value, we should use a formula like below:
CREATE FUNCTION dbo.Length(#x NVARCHAR(MAX)) RETURNS INT
AS
BEGIN
RETURN (CASE WHEN RIGHT(#x, 1) = ' ' THEN LEN(REPLACE(#x, ' ', '$')) ELSE LEN(#x) END)
END
The function is not efficient. I know. But, it returns a correct answer at least.

SQL - Replace string function is not working as intended

I have a simple string; for example,'01023201580001'.
I would like to replace the last two characters of this string; '01', with '00'.
I could extract the last two characters from this string as RIGHT(columname,2) and then use
REPLACE([columname], RIGHT([columname], 2), '00') as newColumnString
But in the result, it replaces the first two characters as well?
Expected result: 01023201580000
Result I get: 00023201580000
What am I doing wrong?
The second argument to the replace() function defines a pattern to match. The function will look for all instances of that pattern in the target string (first argument) and replace them with the replacement text (third argument).
If you know you only need to change the last two characters, you can take the value excluding those characters and then append the characters you want:
select left(columname, len(columname) - 2) + '00';
If you are doing this for an entire column and some of the rows might not end with '01', you can filter those out:
update MyTable
set columname = left(columname, len(columname) - 2) + '00'
where columname like '%01';
You could also use stuff() in a similar way.
In SQL server, you can use substring like so:
DECLARE #s NVARCHAR(20) = N'01023201580001';
DECLARE #ReplaceWith NVARCHAR(20) = N'00';
SELECT SUBSTRING(#s, 0, LEN(#s) - 1) + #ReplaceWith;
Output: 01023201580000

How to use IN condition in SQL Server when comparing Varchars with trailing spaces?

Here is a sample of the issue:
SELECT 'True'
WHERE 'Hello ' IN ('Hello', 'Goodbye', 'Hello ')
Currently this returns 'True' because SQL ignores trailing spaces when comparing VARCHAR. In this related question, this can be solved by using LIKE, however this won't work with an IN condition.
How can I ensure that the comparison takes into account the trailing spaces, specifically when using the IN condition?
Edit:
My list of acceptable values can include items with trailing spaces. Looking to compare exact values essentially (i.e 'Hello ' won't match with 'Hello ')
Assuming that your list of acceptable values do not have trailing spaces, perhaps you could use:
SELECT 'True'
WHERE 'Hello ' IN ('Hello', 'Goodbye') AND 'Hello ' NOT LIKE '% '
You could add a non-space char to the end of your search temrs:
DECLARE #Terminator char(1) = '|';
SELECT 'True'
WHERE 'Hello ' + #Terminator IN ('Hello' + #Terminator , 'Goodbye' + #Terminator)
This will force the comparison to take into account the trailing spaces while keeping everything seargable. (I assume you want to use columns either on the left or on the right side of the IN operator)
I can think of this solution on top of my head:
SELECT 'True'
WHERE reverse('Hello ') IN (reverse('Hello'), reverse('Goodbye'))
Basically this forces to compare string using reverse function.
But Zohar's solution below is most performance driven solution.
SELECT 'True'
WHERE 'Hello '+'|' IN ('Hello'+'|', 'Goodbye'+'|')

Make substring using a specific delimiter in SQL

I want to make a substring of a column value using a specific delimiter.I tried SUBSTRING_INDEX,but it doesn't work for SQL.Is there any way to achieve this??
Column values are:
ARTCSOFT-1111
ARTCSOFT-1112
ARTCSOFT-1113
and I want to achieve the same thing in SQL:
SUBSTRING_INDEX(Code,'SOFT-',1))
i.e I want the number after SOFT- in my substring.I can't use only - because before SOFT- there is chance that - may occur(rare case,but I don't want to take a chance)
Try using just SUBSTRING . For example
SELECT
SUBSTRING(code, CHARINDEX('SOFT-', code) + 5, LEN(code)) AS [name] from dbo.yourtable
hope this helps.
Tested Result:
SELECT RIGHT(Code , CHARINDEX ('-' ,REVERSE(Code))-1)
Read this as: Get the rightmost string after the first '-' in a reversed string - which is the same as the string after the last '-' character.
Try This Query:
select substring(col,charindex('-',col)+1,len(col)-charindex('-',col)) from #Your_table
Explanation of Query:
Here Charindex find the '-' delimeter [length] IN Given String and now that Result[length+1] is our starting point and ending length is [len(col)-starting length] gives ending point and then use substring Function to split a string according to our requirement.
Result of Query:
Required_col
1111
1112
1113

Resources