This is something that has puzzled me.
I have a SP with a TRY-CATCH and if it fails it should insert a record in an error log table with a message and some codes.
This is how it looks like:
INSERT INTO [Errors]
([application]
,[message]
,[extra])
VALUES
('MySP'
,ERROR_MESSAGE()
,'InvNum=' + str(#inumber) + ' -- InvId=' + str(#IID) + ' -- Error Num: ' + str(ERROR_NUMBER()) + ' -- Error Line: ' + str(ERROR_LINE()))
The problem is that every time it tries to run this query it produces a varchar to float conversion error. It doesn't make sense for me because all the values passed in the last column are being converted to string.
Any idea?
Instead of using the STR function on several values and then concatenating the string with the string concatenation operator, use the CONCAT function. It is pretty flexible with regards to what datatypes you pass into it and it should produce the same expected result.
INSERT INTO [Errors] ([application],[message],[extra])
VALUES (
'MySP'
, ERROR_MESSAGE()
, CONCAT('InvNum=',
#inumber,
' -- InvId=',
#IID,
' -- Error Num: ',
ERROR_NUMBER(),
' -- Error Line: ',
ERROR_LINE()
)
)
The problem is that according to the doc, the STR function "Returns character data converted from numeric data". In other words, the parser knows that the STR function requires numeric parameters, so it is trying to convert all of your arguments into floats first and then the STR function will change them into strings.
Personally, I almost never use the STR function because of stuff like this, rather I prefer to use either CAST(.. AS ..) or CONVERT(..) because they 1) care less about the input data type and 2) can produce any output data type based on the parameters. So rather than worry about which function I use to convert from data type (A) to data type (B), I always use the same function (CAST or CONVERT) and just have to worry about getting the parameters right.
Yes, it is true that CAST and CONVERT are a lot clunkier, longer and uglier, but if you just always use CONVERT than you only have to worry about how CONVERT works (also, CONVERT is super-general, you can use it for almost any scalar type conversion).
Related
I load excel file into sql as varchar(max) and got that Scientific e value which now I try to convert into numeric as I need to do compare that value, and here I'm running into problem.
This is main question: How and to what type I can convert this to compare with whole integer value ?
On the pic You can see how this seen in Excel, even formatted to text it somehow still loaded into varchar(max) not like char string. This can be seen from my test code.
DECLARE #C VARCHAR(MAX) = '1.1001562717e+011', #Nc VARCHAR(MAX) = '110015627174';
SELECT #c, LEN(#c) LenC ,
ISNUMERIC(#c) NumYN
---, CAST(#c AS DECIMAL(38,2)) cDec ---CAST(#c AS NUMERIC) cNum --, CAST(#c AS BIGINT) cInt
WHERE #c LIKE '%[^0-9]%'
AND ISNUMERIC(#c) = 1
To start, ISNUMERIC is a terrible function, it does not give good results; it is often wrong. If you try ISNUMERIC('1.1001562717e+011') you'll notice that you get the value 1, however, CONVERT(numeric(13,1),'1.1001562717e+011') will produce an error. A far better function is TRY_CONVERT (or TRY_CAST), which returns NULL if the conversion fails for the specific data type: TRY_CONVERT(numeric(13,1),'1.1001562717e+011').
Being specific on the data type is actually important here, as ISNUMERIC could be (incorrectly) suggesting that the value could be converted to at least 1 of the numeric data types; but that doesn't mean all of them. For scientific data types the only data type you can convert to is a float/real:
SELECT TRY_CONVERT(numeric(13,1),'1.1001562717e+011') AS Numeric,
TRY_CONVERT(bigint,'1.1001562717e+011') AS int,
TRY_CONVERT(float,'1.1001562717e+011') AS float,
TRY_CONVERT(money,'1.1001562717e+011') AS money;
Notice that only float has a value here. As you want a numeric as the final value, then you'll need to CONVERT the value twice:
CONVERT(numeric(13,1),TRY_CONVERT(float,'1.1001562717e+011'))
I have a case statement where I'm trying to SUM multiple column int values and then format the summed value to '00000015700+' as an example but getting a conversion error in SQL Server 2016.
Here is the error:
Conversion failed when converting the varchar value '00000015700+' to
data type int.
Here is my code :
CASE
WHEN x.Code = 'WRITPREM' AND x.[Description] = 'NEW POLICY' THEN RIGHT('00000000000' + CAST(REPLACE((sum(x.totalPolicy_BIN) + sum(x.totalPolicy_COL) + sum(x.totalPolicy_OTC) + sum(x.totalPolicy_PDM) + sum(x.totalPolicy_MED) +sum(x.totalPolicy_PIP) + sum(x.totalPolicy_REN) + sum(x.totalPolicy_TOW) + sum(x.totalPolicy_UBI) + sum(x.totalPolicy_UPD)),'.','') as varchar(12)) + '+',12)END as TEST
Any help/direction would be appreciated. Thanks.
One of the fields that you are sum()ing contains the value with a "+" sign. As a result, SQL Server cannot convert the value to an integer in order to sum(). It seems you are applying the function on a non-numeric column(s). So you have unexpected data in at least one of those columns. Try eliminating some of the sum() columns to figure out which column contains the offending data. Ideally, you'd have the correct data types on each column and not run into this issue.
You have reversed the REPLACE and CAST commands. You should CAST the value to string, then REPLACE the decimal point and add your plus sign to the end, then take the RIGHT(..., 12) of that value.
I have four columns in a table. The table identifies the packaging amounts per box. The four columns are -
ID
PerCase
InnerCarton
PerPack
I want query and create 2 columns ID & Condensed
Column condensed should result in "perCase/InnerCarton/PerPack"
there are many IDs where the InnerCarton is null, so I want the condensed column to show "PerCase/PerPack"
I tried this -
SELECT ID,
CAST(IIf([Items_UOM].[InnerCase] Is Not Null
,[Items_UOM].[PerCase] & '/' & [Items_UOM].[InnerCase] & '/' & [Items_UOM].[PerPack]
,[Items_UOM].[PerCase] & '/' & [Items_UOM].[PerPack]) AS varchar(25))
FROM Items_UOM;
I am getting an error message - Conversion failed when converting the varchar value '/' to data type smallint.
You have several things going on here not quite correct. First, to combine strings you use + not &. Second, you have datatype conversion issues because your columns are tinyint and you can't just add characters to add without an explicit conversion. You can also simplify this by using ISNULL or COALESCE instead of IIF and being forced to repeat the logic.
This should work for you.
SELECT ID,
convert(varchar(25), [Items_UOM].[PerCase]) + ISNULL('/' + [Items_UOM].[InnerCase], '') + '/' + convert(varchar(25), [Items_UOM].[PerPack])
FROM Items_UOM;
& is the binary and operator, not a string concatenation operator.
If CONCAT_NULL_YIELDS_NULL is set you could use + to concatenate the values with the slash and concat() to build the overall string. As with + the concatenation gets NULL if one operand is null the slash gets sort of eliminated for NULLs. concat() however replaces NULLs with an empty string, so the overall result isn't NULL if there are NULL values.
If the values are integers you need to convert them to a string them prior using them in the + as otherwise the + is interpreted as an arithmetic plus and results in the engine trying to convert the '/' to a number, which of course fails.
SELECT id,
concat(convert(varchar(max), items_uom.innercase) + '/',
convert(varchar(max), items_uom.percase) + '/',
convert(varchar(max), items_uom.perpack)
FROM items_uom;
I have observed an peculiar issue in the ISNUMERIC function. Below is the same code:
declare #variable nvarchar(max) = '123,456,789,147,258,369'
if (ISNUMERIC(#variable) = 1 )
select 'numeric' as output
else
select 'char' as output`
Below is the link for demo of the out put and different scenarios
Demo Here
It gives output as Character, though it numeric. Any suggestions for the behavior.
I have observed this behavior only when we copy the numbers and paste it in variable declaration, instead if we just type the number then it works fine.
Demo Here
Your CSV string is just that, a string, despite that it consists of CSV numbers. If you want to verify that you have an all-numeric CSV string you could try removing all commas and then asserting that what remains is a number:
declare #variable nvarchar(max) = '123,456,789,147,258,369'
if (ISNUMERIC(REPLACE(#variable, ',', ''l) = 1 )
select 'numeric' as output
else select 'char' as output
The string you defined, '123,456,789,147,258,369' is not a number, a number cannot have multiple commas.
If you have specific criteria on what do you consider a number, your should build your a user defined function to determine to sort strings as 'numeric' or 'char' according to your criteria.
Best regards,
Sergio
The reason for the behavior you are seeing appears to be due to the length of the string.
After reading this on MSDN:
ISNUMERIC returns 1 when the input expression evaluates to a valid
numeric data type
I ran some tests:
select ISNUMERIC('1,234')
1
select ISNUMERIC('1,234,456')
1
proves that you can have commas in the string
select isnumeric('123,456,789,147,258,369')
0
confirms the behavior you are seeing.
Your string is too big to be an int, but it could be a bigint, so:
select CONVERT(bigint,'123,456,789,147,258,369')
Error converting data type varchar to bigint.
select CONVERT(int,'1,234')
Conversion failed when converting the varchar value '1,234' to data type int.
proves that strings with commas can't be converted to int. What about decimals?
select CONVERT(decimal(10,0),'1,234')
Error converting data type varchar to numeric.
select CONVERT(float,'1,234')
Error converting data type varchar to float.
nope. that leaves money:
select CONVERT(money,'2,234')
2234.00
select CONVERT(money,'2,234,000')
2234000.00
so strings with (multiple) commas can be converted to money. But if the number would be too big to fit in a money datatype:
select CONVERT(money,'123,456,789,147,258,369')
Arithmetic overflow error converting expression to data type money.
then it can't be converted, and if it can't be converted, then ISNUMERIC()=0.
Thanks for your responses .Below is the final solution I got by eliminating the comma, NEXT line char and Space character as below:
declare #variable nvarchar(max) = '21386, 21385, 20178, 20176, 19958, 20026, 19976, 19933, 20029, 19921, 4552, 19784, 4700, 19730, 14655, 4749, 4998, 19604,'
if (ISNUMERIC(REPLACE( replace(REPLACE(REPLACE(#variable, ',' ,'1'), CHAR(10), ''), CHAR(9), ''), CHAR(13), '')) = 1 )
select 'numeric' as output
else select 'char' as output
I'm finding this to be truly bizarre behaviour.
Here is my T-SQL:
declare #testText nvarchar(1000);
set #testText = '17D4,A,1';
select txt_value from fn_ParseText2Table (#testText , ',' )
where fn_ParseText2Table is a function that parses the text into a table where you can get the txt, int, and floating point values, if they work.
The 17D4 is a product code that I'm trying to extract within a larger query, and all other 3817 records work fine.
select (
select txt_value
from fn_ParseText2Table(t.primaryKeyValues , ',' ) as pk
where position = 1) as product_NBR
from database.dbo.tablesToParse as t
where t.tableName = 'ProductData'
I found the function here.
What I've found is that if the string starts with some numbers (I've tested anywhere from 1-4 ) followed by 'D', it fails with the 'Error converting data type varchar to numeric.' message.
All other combinations of text work. Lower case d is fine. C is fine, E, F, etc. So '17F5,A,1' is fine. Also 'asdf 17D5,A,1' is fine. '1D,A,1' is not fine.
I'm very confused. Is there a special escape character in T-SQL for 'D'?
Update:
I should clarify that the error occurs inside fn_ParseText2Table()
Update 2
It's SQL server 10 - 64 bit, running on a windows 2008 server.
As well, I've tested this in a sql mgr query window:
declare #testText nvarchar(1000);
set #testText = '17D4';
select isnumeric( #testText )
The IsNumeric() call returns 1, which is why the fn_ParseText2Table() function tries to cast it to an in and it fails. I could add an extra check to that function to lower the text first and see if that's also numeric.
I figured it was related to floating-point literals but I was surprised it wouldn't cast to a numeric type. I guess it only works when float is the target type. You'll find the explanation here:
http://www.sqlservercentral.com/Forums/Topic202581-8-1.aspx
This behavior doesn't match up with other SQL Server literals, ie, constants:
select 1d -- literal 1 with d treated as the column alias
select 1e -- literal 1.0 as a float
select cast('1d' as float), cast('1e' as float) -- neither of these will cast without an exponent value
select cast('1d0' as float), cast('1e0' as float) -- these work though