LEN() & CHARINDEX() problem in formatting field - sql

I have the following query:
UPDATE P
SET Street = TRIM(LEFT(FormattedAddress, CHARINDEX(',', FormattedAddress)-1)),
Town = TRIM(RIGHT(FormattedAddress, LEN(FormattedAddress)-CHARINDEX(',', FormattedAddress)))
FROM Person P
and it's suddenly started failing with the following error:
Msg 537, Level 16, State 2, Line 3
Invalid length parameter passed to the LEFT or SUBSTRING function.
The statement has been terminated.
How could I find the data that is causing this to fail and fix the update statement so it doesn't fail in the future?

How could I find the data that is causing this to fail and fix the
update statement so it doesn't fail in the future?
Try like this to find. You will get the rows which are breaking your query.
SELECT * FROM
Person P
WHERE CHARINDEX(',', FormattedAddress) <=0
Better way of writing same query as suggested by Jeroen Mostert is like following.
SELECT * FROM
Person P
WHERE FormattedAddress NOT LIKE '%,%'

You are getting the Error because there are values in FormattedAddress which do not have a "," and hence the CHARINDEX function will return the value as 0 for those. since for LEFT,RIGHT and SUBSTRING functions accept only positive integers greater than 0, These rows will throw an Error.
You can easily identify the rows that are causing the issue using the following query
SELECT
*
FROM Person P
WHERE CHARINDEX(',', FormattedAddress) = 0
There are multiple ways you can overcome the same
Approach# 1
Use Case inside the LEFT / RIGHT
UPDATE P
SET
Street = TRIM(LEFT(FormattedAddress,
CASE WHEN CHARINDEX(',', FormattedAddress)>1
THEN CHARINDEX(',', FormattedAddress)-1
ELSE LEN(FormattedAddress) END)
),
Town = TRIM(RIGHT(FormattedAddress,
CASE WHEN CHARINDEX(',', FormattedAddress)>0
THEN LEN(FormattedAddress)-CHARINDEX(',', FormattedAddress)
ELSE LEN(FormattedAddress) END)
)
FROM Person P
Approach# 2
Filter the records in the WHERE clause
UPDATE P
SET
Street = TRIM(LEFT(FormattedAddress, CHARINDEX(',', FormattedAddress)-1)),
Town = TRIM(RIGHT(FormattedAddress, LEN(FormattedAddress)-CHARINDEX(',', FormattedAddress)))
FROM Person P
WHERE CHARINDEX(',', FormattedAddress) > 1

You can use WHERE cease :
WHERE FormattedAddress LIKE '%,%'
However, you can also do :
UPDATE P
SET Street = TRIM(LEFT(FormattedAddress, CHARINDEX(',', FormattedAddress + ',')-1)),
Town = TRIM(RIGHT(FormattedAddress, LEN(FormattedAddress)-CHARINDEX(',', FormattedAddress)))
FROM Person P;

Related

Issue with replacing negative values with zero

Checked similar threads but no similar issues were experienced by other users.
The code does not seem to work and the error message says "Unexpected token 'Then' at line 11".
Lines 6 to 8 get the calculated column that determines the savings but if it is a loss, it becomes negative. I wanted to replace all negative values with 0 using Case but for some reason 'then' is treated as an error.
Select Distinct Reports.rptviewGovtTransparencyCode.project_title As Title,
Reports.rptviewContract.AwardedDateTime As Awarded,
Reports.rptviewContract.estimated_value As Budget,
Convert(decimal,Replace(Reports.rptviewCustomFieldAnswer.Answer, ',',
'')) As Value,
Reports.rptviewContract.estimated_value -
Convert(decimal,Replace(Reports.rptviewCustomFieldAnswer.Answer, ',',
'')) As Saving,
case when (Reports.rptviewContract.estimated_value -
Convert(decimal,Replace(Reports.rptviewCustomFieldAnswer.Answer, ',', ''))
<= 0 then 0) As Saving2
From Reports.rptviewGovtTransparencyCode
Inner Join Reports.rptviewContract On Reports.rptviewContract.contract_id =
Reports.rptviewGovtTransparencyCode.contract_id
Inner Join Reports.rptviewCustomField On Reports.rptviewCustomField.OrgId =
Reports.rptviewContract.OrgId
Inner Join Reports.rptviewCustomFieldAnswer
On Reports.rptviewCustomFieldAnswer.TargetAreaId =
Reports.rptviewContract.project_id And Reports.rptviewCustomField.Id =
Reports.rptviewCustomFieldAnswer.CustomFieldId
Inner Join Reports.rptviewContractPrimaryContact
On Reports.rptviewContract.contract_id =
Reports.rptviewContractPrimaryContact.ContractId
Where Reports.rptviewGovtTransparencyCode.department = '1capital' And
Reports.rptviewCustomField.Title = 'awarded value'
This:
case when (Reports.rptviewContract.estimated_value -
Convert(decimal,Replace(Reports.rptviewCustomFieldAnswer.Answer, ',', ''))
<= 0 then 0)
is missing the case's end, and also has a wrong parenthesis couple enclosing both the coondition and the "then" after the when clause. Replace it with the following:
case when Reports.rptviewContract.estimated_value -
Convert(decimal,Replace(Reports.rptviewCustomFieldAnswer.Answer, ',', ''))
<= 0 then 0 end
In order to demonstrate better, what you had before was:
case when (condition then result)
while the correct was
case when condition then result end
You shall not p...hide the "then" inside the parenthesis: the "when" cannot see it.

View causing Invalid length parameter passed to the LEFT or SUBSTRING function error when providing where clause

I'm having an odd thing occurring in one of my views. Initially, I have a view that does the following:
SELECT id, CAST((CASE WHEN
LEN(line) = 1
THEN ISNULL(LTRIM(RTRIM(line)), '-1')
ELSE
ISNULL(LTRIM(RTRIM(SUBSTRING(line, 1, (CHARINDEX(CHAR(9),
line) - 1)))), '-1')
END) AS varchar(MAX)) AS ObjMarker
FROM dbo.tblM2016_RAW_Current_Import_File
WHERE ((CASE WHEN
LEN(line) = 1
THEN ISNULL(LTRIM(RTRIM(line)), '')
ELSE
LTRIM(RTRIM(SUBSTRING([line], 1, CHARINDEX(CHAR(9), [line]))))
END) <> CHAR(9))
AND
((CASE WHEN
LEN(line) = 1
THEN ISNULL(LTRIM(RTRIM(line)), '')
ELSE
LTRIM(RTRIM(SUBSTRING([line], 1, CHARINDEX(CHAR(9), [line]))))
END) NOT LIKE '%*%')
AND
((CASE WHEN
LEN(line) = 1
THEN ISNULL(LTRIM(RTRIM(line)), '')
ELSE LTRIM(RTRIM(SUBSTRING([line], 1, CHARINDEX(CHAR(9),
[line])))) END) <> '')
And it works fine. However, I have another view which uses the results of the above view, shown below:
SELECT curr.id
,curr.ObjMarker
,Nxt.id AS NxtID
,Nxt.ObjMarker AS NxtObjMarker
,Nxt.id - curr.id - 2 AS OFFSET
,curr.id + 1 AS StrtRec
,Nxt.id - 1 AS EndRec
FROM dbo.vwM2016_RAW_Import_File_Object_Line_Markers AS curr
LEFT OUTER JOIN
dbo.vwM2016_RAW_Import_File_Object_Line_Markers AS Nxt ON
Nxt.id =
(SELECT MIN(id) AS Expr1
FROM dbo.vwM2016_RAW_Import_File_Object_Line_Markers AS source
WHERE (id > curr.id))
WHERE curr.ObjMarker <> '0'
And apparently, if I leave the WHERE curr.ObjMarker <> '0' in the second query, it gives the error
Msg 537, Level 16, State 3, Line 1
Invalid length parameter passed to the LEFT or SUBSTRING function.
But if I remove WHERE curr.ObjMarker <> '0' it returns the result set without error.
Could this be a problem with the query optimizer not doing operations in order? I've checked the rows where 0 occurs for any special characters in an editor and I couldn't find any hidden whitespace characters or anything.
There's no guarantee of the order the criteria in your select statements will be evaluated, and SQL Server does not short circuit. Predicate pushdown can also happen for any criteria SQL Server estimates to be useful -- so you can't assume that a certain criteria will always be evaluated before something else.
The problem is with this expression:
ISNULL(LTRIM(RTRIM(SUBSTRING(line, 1, (CHARINDEX(CHAR(9),
line) - 1)))), '-1')
If [line] does not contain a Char(9), the CharIndex field returns 0. This turns the substring expression into SUBSTRING(line,1,-1), which is invalid because the length cannot be a negative number.
When not used in the WHERE clause, the expression is not evaluated until after the other filters are applied and the result set is reduced. At least one of the filters in the view eliminate the rows without tabs, so the expression never operates on those rows.
However, when the expression is used in the WHERE clause, it is combined with the view filters and evaluated in the order that SQL Server determines is best for performance. Unfortunately, some of the rows without tabs are still part of the result set when this is evaluated, causing the result to fail.
A possible fix, add an explicit test in your case statement (in the first view where you define objMarker) to address rows that do not contain tabs.
WHEN CHARINDEX(CHAR(9), line) = 0 THEN '-1'

Count number of character before 2 #

I have a problem with my query. I need to create a query to count all characters except of all characters between symbol #. For example I have :
#CN#Test
#DATE#hjkjhkjh#DATE#hjkh#SC#hkhkjhkjhkjhkj#SC#
I can have multiple # into an expression
I want to get value 4 not 8, so without #CN#.
I tried :
SELECT e.id as event_id,length(em.value) as num_count
FROM event_mt em
INNER JOIN event e ON e.id = em.id_event
WHERE e.del_date IS NULL
AND em.value not like '%[^0-9]%'
The regex is not correct.
Help me please.
Try this.
DECLARE #str VARCHAR(30)='#CN#Test'
SELECT len(LEFT(#str, Charindex('#', #str)-1) +
+ Reverse(LEFT(Reverse(#str), Charindex('#', Reverse(#str))-1)))
I resolve it with replaces nested :
SELECT e.id as event_id,em.id,
(LENGTH(REPLACE(REPLACE(REPLACE(REPLACE(em.value, 'dfd', ''),'ghgfh',''),'wer',''),'65756',''))) as message_count
FROM event

How to remove the first character if it is a specific character in SQL

I currently have a table Telephone it has entries like the following:
9073456789101
+773456789101
0773456789101
What I want to do is remove only the 9 from the start of all the entries that have a 9 there but leave the others as they are.
any help would be greatly appreciated.
While all other answer are probably also working, I'd suggest to try and use STUFF function to easily replace a part of the string.
UPDATE Telephone
SET number = STUFF(number,1,1,'')
WHERE number LIKE '9%'
SQLFiddle DEMO
Here is the code and a SQLFiddle
SELECT CASE
WHEN substring(telephone_number, 1, 1) <> '9'
THEN telephone_number
ELSE substring(telephone_number, 2, LEN(telephone_number))
END
FROM Telephone
Update Telephone set number = RIGHT(number,LEN(number)-1) WHERE number LIKE '9%';
I recently solved a similar problem with a combination of RIGHT(), LEN() & PATINDEX(). PATINDEX will return the integer 1 when it finds a 9 as the first character and 0 otherwise. This method allows all records to be returned at once without a CASE WHEN statement.
SELECT
RIGHT(number, LEN(number) - PATINDEX('9%', number))
FROM Telephone
UPDATE dbo.Telephone
SET column_name = SUBSTRING(column_name, 2, 255)
WHERE column_name LIKE '9%';
Stuff is a great function for this. However, using it with an update statement with a where clause is great, but what if I was doing an insert, and I needed all of the rows inserted in one pass. The below will remove the first character if it is a period, does not use the slower case statement, and converts nulls to an empty string.
DECLARE #Attachment varchar(6) = '.GIF',
#Attachment2 varchar(6)
SELECT
#Attachment2 = ISNULL(ISNULL(NULLIF(LEFT(#Attachment, 1), '.'), '') + STUFF(#Attachment, 1, 1, ''), '')
SELECT
#Attachment2
DECLARE #STR nvarchar(200) = 'TEST'
SET #STR = STUFF(#STR,1,1,'')
PRINT #STR
Result will be "EST"
You can use replace in select statement instead of where or update
SELECT REPLACE(REPLACE('_'+number,'_9',''),'_','') FROM #tbl

T-SQL Case statement utilizing substring and isnumeric

I have a T-SQL stored proc that supplies a good amount of data to a grid on a .NET page....so much so that I put choices at the top of the page for "0-9" and each letter in the alphabet so that when the user clicks the letter I want to filter my results based on results that begin with that first letter. Let's say we're using product names. So if the user clicks on "A" I only want my stored proc to return results where SUBSTRING(ProductName, 1, 1) = "A".
Where I'm getting hung up is on product names that begin with a number. In that case I want to fetch all ProductName values where ISNUMERIC(SUBSTRING(ProductName, 1, 1)) = 1. I'm using an input parameter called #FL. #FL will either be a zero (we have few products that begin with numerics, so I lump them all together this way).
Of course there's also the alternative of WHERE SUBSTRING(ProductName, 1, 1) IN ('0', '1', '2'.....) but even then, I've never been able to devise a CASE statement that will do an = on one evaluation and an IN statement for the other.
Here's what I have in my proc for the CASE part of my WHERE clause. It doesn't work, but it may be valuable if only from a pseudocode standpoint.
Thanks in advance for any ideas you may have.
AND CASE #FL
WHEN "0" THEN
CASE WHEN #FL = "0" THEN
isnumeric(substring(dbo.AssnCtrl.Name, 1, 1)) = 1
ELSE
SUBSTRING(dbo.AssnCtrl.Name, 1, 1) = #FL
END
END
*** I know that this use of the CASE statement is "non-standard", but I found it online and thought it had some promise. But attempts to use a single CASE statement yielded the same result (an error near '=').
Why not just use Like operator ?
Where dbo.AssnCtrl.Name Like #FL + '%'
When they select the Any Number option, pass in #FL as '[0-9]'
(I assume you have an index on this name column ?)
To steal a bit from Charles:
AND Substring(dbo.AssnCtrl.Name, 1, 1) Like
CASE WHEN #FL = '0' THEN '[0-9]'
ELSE #FL
END
Have you tried
AND (
isnumeric(substring(dbo.AssnCtrl.Name, 1, 1)) = 1
or
SUBSTRING(dbo.AssnCtrl.Name, 1, 1) = #FL )
this works for me:
select * from casefile where
isnumeric(substring(pmin,1,1)) = 1
or
substring(pmin,1,1) = 'a'