Conversion error despite using CAST? - sql

I have a cursor which fetches reference codes from a table and increments the code by one if it fits certain criteria. The reference is alphanumeric so it is declared as nvarchar.
To keep things simple, assume that #RefNo = 'v1', with the intention of changing this to v2:
DECLARE #versionNo INT
DECLARE #RefNo nvarchar(50)
DECLARE #NewVersionNo INT
DECLARE #NewRefNo nvarchar(50)
set #VersionNo = Right(#RefNo, 1)
set #NewVersionNo = #versionNo + 1
set #NewRefNo = Left(#RefNo, Len(#RefNo - 1)) + cast(#NewVersionNo as nvarchar)
print #NewRefNo
The final line fails with error Conversion failed when converting the nvarchar value 'v1' to data type int. To an extent I get why this is happening - the '+' operator can't handle nvarchar and int values at the same time - but I would have thought the cast to nvarchar on #NewVersionNo would have avoided that.
Also note that I am using 2008R2 so am unable to use the CONCAT function.

you have miss place closing bracket, change your code of line as below
set #NewRefNo = Left(#RefNo, Len(#RefNo) - 1) + cast(#NewVersionNo as nvarchar)
-----------^
If #RefNo='V1'
Output:

Related

I want to print table of 17 from 3 to 17 but my code throws error not converting 'x' and '=' into int

declare #table int
set #table = 17
declare #loop int
set #loop = 3
declare #x varchar
set #x = 'x'
while(#loop <= 17)
begin
print #table + cast(#x as varchar) + #loop + cast(' = ' as char) + #table * #loop
end
In this code you see #x and '=' which is not converting into int.
I get this error instead:
Msg 245, Level 16, State 1, Line 67
Conversion failed when converting the varchar value 'x' to data type int.
I tried to convert #x to int as well as I changed data type of variable but it didn't work so far.
So I tried to put values of x and = into variables and change datatype on earlier stage but same problem occurred every time
declare #table int
set #table=17
declare #loop int
set #loop=3
while(#loop<=17)
begin
print concat( #table ,'x',+#loop,'=', +#table*#loop)
set #loop+=1
end
When I see problem I got an mistake on print statement where I was using only variables but I didn't realize they all should have same datatype that what the problem I thought so I researched for concat keyword.
it automatically converts all variables and values in between to datatype that is being required so I used
print concat(#table ,'x',+#loop,'=', +#table*#loop)

Reverse substring

I am trying to extract some characters from a string.
For Example in (316409953_ND_02142022_000001.pdf) I need the characters after the last underscore _ and before the "."
Answer: 000001
#test = 316409953_ND_02142022_000001.pdf
I have tried:
REVERSE(SUBSTRING(REVERSE(test),CHARINDEX('.',REVERSE(test))+1,CHARINDEX('_',REVERSE(test)+1)))
I need help with the last part of substring. First error I am getting is "Conversion failed when converting the varchar value 'fdp.100000_22024120_DN_359904613' to data type int."
Secondly I need it to pick only after the last "_"
Please guide or let me know if there's another way to do this.
This looks like SQL Server.
On that assumption, and using the single example value, you can try the follolwing:
declare #test varchar(50) = '316409953_ND_02142022_000001.pdf'
select #test OriginalValue,
ParseName(Right(#test, CharIndex('_',Reverse(#test))-1),2) ExtractedValue;
it isn't pretty but it does the job ;P
declare #str varchar(200) = '316409953_ND_02142022_000001.pdf'
declare #tempStr varchar(200)= (select SUBSTRING(#str,LEN(#str) + 2 - CHARINDEX('_',REVERSE(#str)),LEN(#str)))
set #tempStr = SUBSTRING(#tempStr,1,CHARINDEX('.',#tempStr) - 1)
select #tempStr

Extract substring from string if certain characters exists SQL

I have a string:
DECLARE #UserComment AS VARCHAR(1000) = 'bjones marked inspection on system UP for site COL01545 as Refused to COD won''t pay upfront :Routeid: 12 :Inspectionid: 55274'
Is there a way for me to extract everything from the string after 'Inspectionid: ' leaving me just the InspectionID to save into a variable?
Your example doesn't quite work correctly. You defined your variable as varchar(100) but there are more characters in your string than that.
This should work based on your sample data.
DECLARE #UserComment AS VARCHAR(1000) = 'bjones marked inspection on system UP for site COL01545 as Refused to COD won''t pay upfront :Routeid: 12 :Inspectionid: 55274'
select right(#UserComment, case when charindex('Inspectionid: ', #UserComment, 0) > 0 then len(#UserComment) - charindex('Inspectionid: ', #UserComment, 0) - 13 else len(#UserComment) end)
I would do this as:
select stuff(#UserComment, 1, charindex(':Inspectionid: ', #UserComment) + 14, '')
This works even if the string is not found -- although it will return the whole string. To get an empty string in this case:
select stuff(#UserComment, 1, charindex(':Inspectionid: ', #UserComment + ':Inspectionid: ') + 14, '')
Firstly, let me say that your #UserComment variable is not long enough to contain the text you're putting into it. Increase the size of that first.
The SQL below will extract the value:
DECLARE #UserComment AS VARCHAR(1000); SET #UserComment = 'bjones marked inspection on system UP for site COL01545 as Refused to COD won''t pay upfront :Routeid: 12 :Inspectionid: 55274'
DECLARE #pos int
DECLARE #InspectionId int
DECLARE #IdToFind varchar(100)
SET #IdToFind = 'Inspectionid: '
SET #pos = CHARINDEX(#IdToFind, #UserComment)
IF #pos > 0
BEGIN
SET #InspectionId = CAST(SUBSTRING(#UserComment, #pos+LEN(#IdToFind)+1, (LEN(#UserComment) - #pos) + 1) AS INT)
PRINT #InspectionId
END
You could make the above code into a SQL function if necessary.
If the Inspection ID is always 5 digits then the last argument for the Substring function (length) can be 5, i.e.
SELECT SUBSTRING(#UserComment,PATINDEX('%Inspectionid:%',#UserComment)+14,5)
If the Inspection ID varies (but is always at the end - which your question slightly implies), then the last argument can be derived by subtracting the position of 'InspectionID:' from the overall length of the string. Like this:
SELECT SUBSTRING(#UserComment,PATINDEX('%Inspectionid:%',#UserComment)+14,LEN(#usercomment)-(PATINDEX('%Inspectionid:%',#UserComment)+13))

How to format the SQL PRINT messages -- a kind of C printf()?

... Well, not exactly only for PRINT. I need to assign a string variable the value that mixes explicit substrings with integer values (and possibly with other type values). The goal is to get the string for logging.
So far, I use the code like:
DECLARE #msg nvarchar(1000)
...
SET #msg = #procname + 'result = ' + CAST(#result AS nvarchar(5))
+ '; error = ' + CAST(#error AS nvarchar(5))
where the #procname is a string like sp_my_proc:, and the #result and the #error are integer variables. The result should look like (no extra spaces around the numbers, just the minimum length):
sp_my_proc: result = 3; error = 0
The above approach works, but... Is there any better way for converting an integer variable to the string than CAST(#result AS nvarchar(5))? (Consider the magic number 5 being a minor detail to be ignored.)
How do you solve the problem of generating such strings in your code?
Thanks, Petr
In SQL-Server you can use STR() function
http://msdn.microsoft.com/ru-ru/library/ms189527.aspx
The default value for 'length' parameter is 10. Since an integer variable is never longer than 10 symbols (you'd have an overflow) this will always work without errors:
declare #test int
set #test = 333333333
select STR(#test)
Also, take a look at
String.Format like functionality in T-SQL?

Convert Numeric into Rowversion / Timestamp

Using SQL Server 2008+.
I have a rowversion column (aka timestamp) which I retrieve from the database and convert into into a numeric(20,0) using the following code:
CONVERT(NUMERIC(20,0), RowVersionColumn + 0) AS [RowVersion]
Later on, I need to take that numeric value (which is stored in a ADO.NET DataSet as a ulong/UInt64), and convert it back into a rowversion data type.
This creates problems, though. It seems as though while you can convert out to numeric(20,0), the reverse operation fails to yield the correct value. For instance:
DECLARE #MyNumericValue NUMERIC(20,0)
DECLARE #MyRowVersionValue ROWVERSION
SET #MyNumericValue = 12345
SET #MyRowVersionValue = CONVERT(rowversion, #MyNumericValue)
PRINT CONVERT(NUMERIC(20,0), #MyRowVersionValue + 0)
Running this code prints out a value of 959447040, not 12345. Removing the "+ 0" from the CONVERT statement yeilds the correct result, but I'm still unable to reliably take a numeric value that used to be a rowversion and turn it back into a rowversion whose value is what it should be.
Below is an even better demonstration of this issue:
DECLARE #MyNumericValue NUMERIC(20,0)
DECLARE #MyRowVersionValue ROWVERSION
DECLARE #MyRowVersionValue2 ROWVERSION
SET #MyRowVersionValue = ##DBTS
SET #MyNumericValue = CONVERT(NUMERIC(20,0), #MyRowVersionValue + 0)
SET #MyRowVersionValue2 = CONVERT(rowversion, #MyNumericValue)
SELECT #MyRowVersionValue
SELECT #MyNumericValue
SELECT #MyRowVersionValue2
Your results will vary depending on your inputs, but as an example my output was:
0x0000000003ADBB2F
61717295
0x140000012FBBAD03
The first and last values should match, but they don't. I'm guessing this has something to do with the fact that binary data conversions often result in padding, and this padding changes the value. See:
http://msdn.microsoft.com/en-us/library/aa223991(v=SQL.80).aspx
Thoughts?
EDIT: To clarify, the fact I'm dealing with rowversion/timestamp is incidental. This same issue happens with BINARY(8) instead of ROWVERSION, as they're equivalent data types.
While I don't understand why you would be converting a meaningless ROWVERSION value to a number and then back again, did you try with BIGINT - which matches the 8 bytes required by UInt64 and not the variable number of bytes (depending on the actual value) that forcing NUMERIC(20,0) would change it to?
CREATE TABLE dbo.rv(a INT, rv ROWVERSION);
INSERT dbo.rv(a) SELECT 1 UNION SELECT 2;
WITH x AS
(
SELECT
rv,
rv_as_bigint = CONVERT(BIGINT, rv)
FROM dbo.rv
)
SELECT
rv,
rv_as_bigint,
rv_back_to_rv = CONVERT(ROWVERSION, rv_as_bigint)
FROM x;
DROP TABLE dbo.rv;
Or taking your original sample and just swapping BIGINT in for NUMERIC(20,0):
DECLARE #MyNumericValue BIGINT
DECLARE #MyRowVersionValue ROWVERSION
DECLARE #MyRowVersionValue2 ROWVERSION
SET #MyRowVersionValue = ##DBTS
SET #MyNumericValue = CONVERT(BIGINT, #MyRowVersionValue) -- removed the +0 hack
SET #MyRowVersionValue2 = CONVERT(rowversion, #MyNumericValue)
SELECT #MyRowVersionValue
SELECT #MyNumericValue
SELECT #MyRowVersionValue2
When you convert data to binary (rowversion is essentially binary(8)), you get its internal representation rather than the logical value. You can verify the behavior with the following snippet:
DECLARE #MyNumericValue NUMERIC(20,0) = 0
SELECT #MyNumericValue, CONVERT(binary(8), #MyNumericValue)
Or you can try
DECLARE #MyBinary binary(8) = 0x00
SELECT #MyBinary, CONVERT(numeric(20,0), #MyBinary)
It won't convert at all.
So, what is really going on with your script is:
SET #MyNumericValue = 12345
-- #MyRowVersionValue gets the internal representation of the numeric value 12345
SET #MyRowVersionValue = CONVERT(rowversion, #MyNumericValue)
-- +0 converts the binary value to int, then performs int-to-numeric conversion
PRINT CONVERT(NUMERIC(20,0), #MyRowVersionValue + 0)
-- Real binary-to-numeric conversion.
PRINT CONVERT(NUMERIC(20,0), #MyRowVersionValue)
The real binary-to-numeric conversion is safe, but in your case, you may want to convert the rowversion to a bigint (or forget about the numeric value and just store it as a binary string) rather than numeric, since CONVERT(NUMERIC(20,0), #MyRowVersionValue) doesn't really get you the numeric value.