MS SQL change Cast count VarChar to % - sql-server

In the last line of the code I have listed below, The current result is blank because the result is less than 1. I need the results to display as a percentage but I'm not sure how. Any suggestions are greatly appreciated?
SELECT
'1,*'+char(13)+char(10)
+'80,1006058'+char(13)+char(10)
+'100,10'+char(13)+char(10)
+'2405,'+cast(count(distinct adt.PAT_ENC_CSN_ID) / 420 as varchar(18))+char(13)+char(10) --Census events --as varchar(10)

The issue is that your count(distinct adt.PAT_ENC_CSN_ID) returns an integer value and then you divide by 420. Another integer.
If you cast the count distinct as a decimal or float, this should solve your issue. CAST(COUNT(DISTINCT adt.PAT_ENC_CSN_ID) AS FLOAT).

SELECT
'1,*'+char(13)+char(10)
+'80,1006058'+char(13)+char(10)
+'100,10'+char(13)+char(10)
+'2405,'+cast( cast(count(distinct adt.PAT_ENC_CSN_ID) AS FLOAT) / cast(420 AS FLOAT) as varchar(18))+char(13)+char(10) --Census events --as varchar(10)
You should cast() your numbers as float otherwise they are considered as integers and you don't have decimals in your division because the result is also considered integer

Just replace this part
cast(count(distinct adt.PAT_ENC_CSN_ID) / 420 as varchar(18))
with
cast(count(distinct adt.PAT_ENC_CSN_ID) / 420.00 as varchar(18))
Note that all we did was turn 420 to 420.00 to suggest SQL to retain decimal part and not treat the result as integer.
As count return integer values and integer/integer is an integer but integer/decimal is decimal

Related

Cast everything for 2 decimal points?

I want to divide two integers: 8/15 and return "53.33".
I've tried every single combination, and I've found that this is the only way I can return the desired value:
select cast(100*cast(8/cast(15 as decimal(10,4)) as decimal(18,4)) as decimal(18,2))
Is there a shorter way?
Thanks.
You are doing interger division. Use float, and multiply by 100.
select 8/15.00 * 100
Or, for your precision, just do the cast once
select cast(8/15.00 * 100 as decimal (10,2))
If these are integers in a table then multiple by 1.0 and cast once
DEMO
declare #table table (int_one int, int_two int)
insert into #table
values
(8,15)
select
cast(((int_one * 1.0) / int_two) * 100 as decimal(10,2))
from #table
try this:
select (cast (8 as money)/cast(15 as money) * 100)

Converting a decimal to a integer

How can I safely convert the following:
ISNULL(t1.UserPercentage,0) AS UserPercentage
Current the t1.UserPecentage column is a decimal(9,2), I want to convert it to an integer.
Since the value can be NULL, the conversion should be done based on the result of the call to ISNULL correct?
DECLARE #Var DECIMAL(9,2) = 2.67
SELECT CAST(ROUND(#Var,0) AS INT)
This query will keep nulls but If you want to convert NULLS into 0
THEN
SELECT CAST(ROUND(ISNULL(#Var, 0),0) AS INT)
Note
Converting DECIMAL to int without ROUNDing it will give you a bit less
accurate result then if you ROUND it to zero before you cast it as
int.
Direct conversion into INT will simply truncate any decimals but if
you ROUND it to zero 1st and then CAST as int , it will give you more
realistic results.
Example
DECLARE #Var DECIMAL(9,2) = 2.67
SELECT CAST(#Var AS INT)
This will return 2, but basic rules of mathematics says this value is 3 if it is rounded to a whole number.
DECLARE #Var DECIMAL(9,2) = 2.67
SELECT CAST(ROUND(#Var,0) AS INT)
This query will return 3. More accurate then just converting it to INT.
If your desired result is a simple truncation of the decimal points, using FLOOR is your best option. At first glance, it would be more obvious to other people what you're trying to do.
ISNULL(FLOOR(t1.UserPercentage), 0) AS UserPercentage
Examples:
SELECT FLOOR(1.1), FLOOR(1.9)
-- Result is a simple truncation of the decimal points. (=1)
declare #val decimal(9,2) =43.44
select convert(int, #val)
or
select cast(#val as int)

Why is casting from float to varchar being rounded in SQL Server?

The following SQL,
declare #a as float, #b as float
select #a=1.353954 , #b=1.353956
select
CAST(#a as VARCHAR(40)) AS a_float_to_varchar ,
CAST(#b as VARCHAR(40)) AS b_float_to_varchar
results in
a_float_to_varchar b_float_to_varchar
---------------------------------------- ----------------------------------------
1.35395 1.35396
based on 'float' and 'real' (Transact-SQL).
Float has a precision of 15 digits, so I am not sure why the number is being rounded when converted to varchar.
Also from your link (it's actually the first line):
Approximate-number data types...
If you want exact precision, don't use float.
That being said, there is a function STR() specifically for converting float to a character data type.
Cast to decimal before casting to varchar:
declare #a as float, #b as float
select #a=1.353954 , #b=1.353956
select
CAST(CAST(#a AS DECIMAL(38,18)) as VARCHAR(40)) AS a_float_to_varchar ,
CAST(CAST(#b AS DECIMAL(38,18)) as VARCHAR(40)) AS b_float_to_varchar
You can specify style to include more digits.
declare #gg float
set #gg = 124.323125453
SELECT #gg,Convert(varchar, #gg,128)
For newer versions of SQL Server, use SELECT #gg,Convert(varchar, #gg,3)
returns
124.323125453 124.323125453
Reference: CAST and CONVERT (Transact-SQL)
Or with STR():
declare #gg float
set #gg = 124.323124354234524
SELECT #gg,str(#gg,16,15)
It should give you all the possible digits. 16 is the total possible length (includes period) while 15 places after the decimal is possible (actually 0.2323... the 0 count toward length, so the length needs to be 17 if all numbers are less that 1). STR(), however, pads the results with leading spaces and trailing 0.

Decimal values in SQL for dividing results

In SQL, I have col1 and col2. Both are integers.
I want to do like:
select col1/col2 from tbl1
I get the result 1 where col1=3 and col2=2
The result I want is 1.1
I put round(col1/col2,2). The result is still 1.
I put decimal(col1/col2,2). The decimal is not built in function.
How can I do exactly to get 1.1?
Just another approach:
SELECT col1 * 1.0 / col2 FROM tbl1
Multiplying by 1.0 turns an integer into a float numeric(13,1) and so works like a typecast, but most probably it is slower than that.
A slightly shorter variation suggested by Aleksandr Fedorenko in a comment:
SELECT col1 * 1. / col2 FROM tbl1
The effect would be basically the same. The only difference is that the multiplication result in this case would be numeric(12,0).
Principal advantage: less wordy than other approaches.
You will need to cast or convert the values to decimal before division. Take a look at this
http://msdn.microsoft.com/en-us/library/aa226054.aspx
For example
DECLARE #num1 int = 3 DECLARE #num2 int = 2
SELECT #num1/#num2
SELECT #num1/CONVERT(decimal(4,2), #num2)
The first SELECT will result in what you're seeing while the second SELECT will have the correct answer 1.500000
SELECT CAST (col1 as float) / col2 FROM tbl1
One cast should work. ("Less is more.")
From Books Online:
Returns the data type of the argument with the higher precedence. For more information about data type precedence, see Data Type Precedence (Transact-SQL).
If an integer dividend is divided by an integer divisor, the result is an integer that has any fractional part of the result truncated
CAST( ROUND(columnA *1.00 / columnB, 2) AS FLOAT)
There may be other ways to get your desired result.
Declare #a int
Declare #b int
SET #a = 3
SET #b=2
SELECT cast((cast(#a as float)/ cast(#b as float)) as float)
just convert denominator to decimal before division e.g
select col1 / CONVERT(decimal(4,2), col2) from tbl1

CAST and IsNumeric

Why would the following query return "Error converting data type varchar to bigint"? Doesn't IsNumeric make the CAST safe? I've tried every numeric datatype in the cast and get the same "Error converting..." error. I don't believe the size of the resulting number is a problem because overflow is a different error.
The interesting thing is, in management studio, the results actually show up in the results pane for a split second before the error comes back.
SELECT CAST(myVarcharColumn AS bigint)
FROM myTable
WHERE IsNumeric(myVarcharColumn) = 1 AND myVarcharColumn IS NOT NULL
GROUP BY myVarcharColumn
Any thoughts?
IsNumeric returns 1 if the varchar value can be converted to ANY number type. This includes int, bigint, decimal, numeric, real & float.
Scientific notation could be causing you a problem. For example:
Declare #Temp Table(Data VarChar(20))
Insert Into #Temp Values(NULL)
Insert Into #Temp Values('1')
Insert Into #Temp Values('1e4')
Insert Into #Temp Values('Not a number')
Select Cast(Data as bigint)
From #Temp
Where IsNumeric(Data) = 1 And Data Is Not NULL
There is a trick you can use with IsNumeric so that it returns 0 for numbers with scientific notation. You can apply a similar trick to prevent decimal values.
IsNumeric(YourColumn + 'e0')
IsNumeric(YourColumn + '.0e0')
Try it out.
SELECT CAST(myVarcharColumn AS bigint)
FROM myTable
WHERE IsNumeric(myVarcharColumn + '.0e0') = 1 AND myVarcharColumn IS NOT NULL
GROUP BY myVarcharColumn
Background:
I use a 3rd Party database which constantly recieves new data from other 3rd party vendors.
It's my job to parse out a horrendous varchar field used to store results.
We want to parse out as much data as possible, and this solution shows you how you can "clean up" the data so that valid entries do not get overlooked.
Some results are free-texted.
Some are Enumerations (Yes, No, Blue, Black, etc..).
Some are Integers.
Others use decimals.
Many are percentages, which if converted to an integer could trip you up later.
If I need to query for a given decimal range (say -1.4 to 3.6 where applicable) my options are limited.
I updated my query below to use #GMastros suggestion to append 'e0'.
Thanks #GMastros, this saved me an extra 2 lines of logic.
Solution:
--NOTE: I'd recommend you use this to convert your numbers and store them in a separate table (or field).
-- This way you may reuse them when when working with legacy/3rd-party systems, instead of running these calculations on the fly each time.
SELECT Result.Type, Result.Value, Parsed.CleanValue, Converted.Number[Number - Decimal(38,4)],
(CASE WHEN Result.Value IN ('0', '1', 'True', 'False') THEN CAST(Result.Value as Bit) ELSE NULL END)[Bit],--Cannot convert 1.0 to Bit, it must be in Integer format already.
(CASE WHEN Converted.Number BETWEEN 0 AND 255 THEN CAST(Converted.Number as TinyInt) ELSE NULL END)[TinyInt],
(CASE WHEN Converted.Number BETWEEN -32768 AND 32767 AND Result.Value LIKE '%\%%' ESCAPE '\' THEN CAST(Converted.Number / 100.0 as Decimal(9,4)) ELSE NULL END)[Percent],
(CASE WHEN Converted.Number BETWEEN -32768 AND 32767 THEN CAST(Converted.Number as SmallInt) ELSE NULL END)[SmallInt],
(CASE WHEN Converted.Number BETWEEN -214748.3648 AND 214748.3647 THEN CAST(Converted.Number as SmallMoney) ELSE NULL END)[SmallMoney],
(CASE WHEN Converted.Number BETWEEN -2147483648 AND 2147483647 THEN CAST(Converted.Number as Int) ELSE NULL END)[Int],
(CASE WHEN Converted.Number BETWEEN -2147483648 AND 2147483647 THEN CAST(CAST(Converted.Number as Decimal(10)) as Int) ELSE NULL END)[RoundInt],--Round Up or Down instead of Truncate.
(CASE WHEN Converted.Number BETWEEN -922337203685477.5808 AND 922337203685477.5807 THEN CAST(Converted.Number as Money) ELSE NULL END)[Money],
(CASE WHEN Converted.Number BETWEEN -9223372036854775808 AND 9223372036854775807 THEN CAST(Converted.Number as BigInt) ELSE NULL END)[BigInt],
(CASE WHEN Parsed.CleanValue IN ('1', 'True', 'Yes', 'Y', 'Positive', 'Normal') THEN CAST(1 as Bit)
WHEN Parsed.CleanValue IN ('0', 'False', 'No', 'N', 'Negative', 'Abnormal') THEN CAST(0 as Bit) ELSE NULL END)[Enum],
--I couln't use just Parsed.CleanValue LIKE '%e%' here because that would match on "True" and "Negative", so I also had to match on only allowable characters. - 02/13/2014 - MCR.
(CASE WHEN ISNUMERIC(Parsed.CleanValue) = 1 AND Parsed.CleanValue LIKE '%e%' THEN Parsed.CleanValue ELSE NULL END)[Exponent]
FROM
(
VALUES ('Null', NULL), ('EmptyString', ''), ('Spaces', ' - 2 . 8 % '),--Tabs and spaces mess up IsNumeric().
('Bit', '0'), ('TinyInt', '123'), ('Int', '123456789'), ('BigInt', '1234567890123456'),
--('VeryLong', '12345678901234567890.1234567890'),
('VeryBig', '-1234567890123456789012345678901234.5678'),
('TooBig', '-12345678901234567890123456789012345678.'),--34 (38-4) is the Longest length of an Integer supported by this query.
('VeryLong', '-1.2345678901234567890123456789012345678'),
('TooLong', '-12345678901234567890.1234567890123456789'),--38 Digits is the Longest length of a Number supported by the Decimal data type.
('VeryLong', '000000000000000000000000000000000000001.0000000000000000000000000000000000000'),--Works because Casting ignores leading zeroes.
('TooLong', '.000000000000000000000000000000000000000'),--Exceeds the 38 Digit limit for all Decimal types after the decimal-point.
--Dot(.), Plus(+), Minus(-), Comma(,), DollarSign($), BackSlash(\), Tab(0x09), and Letter-E(e) all yeild false-posotives with IsNumeric().
('Decimal', '.'), ('Decimal', '.0'), ('Decimal', '3.99'),
('Positive', '+'), ('Positive', '+20'),
('Negative', '-'), ('Negative', '-45'), ('Negative', '- 1.23'),
('Comma', ','), ('Comma', '1,000'),
('Money', '$'), ('Money', '$10'),
('Percent', '%'), ('Percent', '110%'),--IsNumeric will kick out Percent(%) signs.
('BkSlash', '\'), ('Tab', CHAR(0x09)),--I've actually seen tab characters in our data.
('Exponent', 'e0'), ('Exponent', '100e-999'),--No SQL-Server datatype could hold this number, though it is real.
('Enum', 'True'), ('Enum', 'Negative')
) AS Result(Type, Value)--O is for Observation.
CROSS APPLY
( --This Step is Optional. If you have Very Long numbers with tons of leading zeros, then this is useful. Otherwise is overkill if all the numbers you want have 38 or less digits.
--Casting of trailing zeros count towards the max 38 digits Decimal can handle, yet Cast ignores leading-zeros. This also cleans up leading/trailing spaces. - 02/25/2014 - MCR.
SELECT LTRIM(RTRIM(SUBSTRING(Result.Value, PATINDEX('%[^0]%', Result.Value + '.'), LEN(Result.Value))))[Value]
) AS Trimmed
CROSS APPLY
(
SELECT --You will need to filter out other Non-Keyboard ASCII characters (before Space(0x20) and after Lower-Case-z(0x7A)) if you still want them to be Cast as Numbers. - 02/15/2014 - MCR.
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(Trimmed.Value,--LTRIM(RTRIM(Result.Value)),
(CHAR(0x0D) + CHAR(0x0A)), ''),--Believe it or not, we have people that press carriage return after entering in the value.
CHAR(0x09), ''),--Apparently, as people tab through controls on a page, some of them inadvertently entered Tab's for values.
' ', ''),--By replacing spaces for values (like '- 2' to work), you open the door to values like '00 12 3' - your choice.
'$', ''), ',', ''), '+', ''), '%', ''), '/', '')[CleanValue]
) AS Parsed--P is for Parsed.
CROSS APPLY
( --NOTE: I do not like my Cross-Applies to feed into each other.
-- I'm paranoid it might affect performance, but you may move this into the select above if you like. - 02/13/2014 - MCR.
SELECT (CASE WHEN ISNUMERIC(Parsed.CleanValue + 'e0') = 1--By concatenating 'e0', I do not need to check for: Parsed.CleanValue NOT LIKE '%e%' AND Parsed.CleanValue NOT IN ('.', '-')
-- If you never plan to work with big numbers, then could use Decimal(19,4) would be best as it only uses 9 storage bytes compared to the 17 bytes that 38 precision requires.
-- This might help with performance, especially when converting a lot of data.
AND CHARINDEX('.', REPLACE(Parsed.CleanValue, '-', '')) - 1 <= (38-4)--This is the Longest Integer supported by Decimal(38,4)).
AND LEN(REPLACE(REPLACE(Parsed.CleanValue, '-', ''), '.', '')) <= 38--When casting to a Decimal (of any Precision) you cannot exceed 38 Digits. - 02/13/2014 - MCR.
THEN CAST(Parsed.CleanValue as Decimal(38,4))--Scale of 4 used is the max that Money has. This is the biggest number SQL Server can hold.
ELSE NULL END)[Number]
) AS Converted--C is for Converted.
Output:
The screenshot below was formatted and cut down to fit on StackOverflow.
The actual results have more columns.
Research:
Next to each query is the result.
It's interesting to see IsNumeric's shortcomings as well as CASTing's limitations.
I show this so you may see the background research that went into writing the query above.
It's important to understand each design decision (in case you're thinking of cutting anything out).
SELECT ISNUMERIC('')--0. This is understandable, but your logic may want to default these to zero.
SELECT ISNUMERIC(' ')--0. This is understandable, but your logic may want to default these to zero.
SELECT ISNUMERIC('%')--0.
SELECT ISNUMERIC('1%')--0.
SELECT ISNUMERIC('e')--0.
SELECT ISNUMERIC(' ')--1. --Tab.
SELECT ISNUMERIC(CHAR(0x09))--1. --Tab.
SELECT ISNUMERIC(',')--1.
SELECT ISNUMERIC('.')--1.
SELECT ISNUMERIC('-')--1.
SELECT ISNUMERIC('+')--1.
SELECT ISNUMERIC('$')--1.
SELECT ISNUMERIC('\')--1. '
SELECT ISNUMERIC('e0')--1.
SELECT ISNUMERIC('100e-999')--1. No SQL-Server datatype could hold this number, though it is real.
SELECT ISNUMERIC('3000000000')--1. This is bigger than what an Int could hold, so code for these too.
SELECT ISNUMERIC('1234567890123456789012345678901234567890')--1. Note: This is larger than what the biggest Decimal(38) can hold.
SELECT ISNUMERIC('- 1')--1.
SELECT ISNUMERIC(' 1 ')--1.
SELECT ISNUMERIC('True')--0.
SELECT ISNUMERIC('1/2')--0. No love for fractions.
SELECT CAST('e0' as Int)--0. Surpise! Casting to Decimal errors, but for Int is gives us zero, which is wrong.
SELECT CAST('0e0' as Int)--0. Surpise! Casting to Decimal errors, but for Int is gives us zero, which is wrong.
SELECT CAST(CHAR(0x09) as Decimal(12,2))--Error converting data type varchar to numeric. --Tab.
SELECT CAST(' 1' as Decimal(12,2))--Error converting data type varchar to numeric. --Tab.
SELECT CAST(REPLACE(' 1', CHAR(0x09), '') as Decimal(12,2))--Error converting data type varchar to numeric. --Tab.
SELECT CAST('' as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST('' as Int)--0. Surpise! Casting to Decimal errors, but for Int is gives us zero, which is wrong.
SELECT CAST(',' as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST('.' as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST('-' as Decimal(12,2))--Arithmetic overflow error converting varchar to data type numeric.
SELECT CAST('+' as Decimal(12,2))--Arithmetic overflow error converting varchar to data type numeric.
SELECT CAST('$' as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST('$1' as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST('1,000' as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST('- 1' as Decimal(12,2))--Error converting data type varchar to numeric. (Due to spaces).
SELECT CAST(' 1 ' as Decimal(12,2))--1.00 Leading and trailing spaces are okay.
SELECT CAST('1.' as Decimal(12,2))--1.00
SELECT CAST('.1' as Decimal(12,2))--0.10
SELECT CAST('-1' as Decimal(12,2))--1.00
SELECT CAST('+1' as Decimal(12,2))--1.00
SELECT CAST('True' as Bit)--1
SELECT CAST('False' as Bit)--0
--Proof: The Casting to Decimal cannot exceed 38 Digits, even if the precision is well below 38.
SELECT CAST('1234.5678901234567890123456789012345678' as Decimal(8,4))--1234.5679
SELECT CAST('1234.56789012345678901234567890123456789' as Decimal(8,4))--Arithmetic overflow error converting varchar to data type numeric.
--Proof: Casting of trailing zeros count towards the max 38 digits Decimal can handle, yet it ignores leading-zeros.
SELECT CAST('.00000000000000000000000000000000000000' as Decimal(8,4))--0.0000 --38 Digits after the decimal point.
SELECT CAST('000.00000000000000000000000000000000000000' as Decimal(8,4))--0.0000 --38 Digits after the decimal point and 3 zeros before the decimal point.
SELECT CAST('.000000000000000000000000000000000000000' as Decimal(8,4))--Arithmetic overflow error converting varchar to data type numeric. --39 Digits after the decimal point.
SELECT CAST('1.00000000000000000000000000000000000000' as Decimal(8,4))--Arithmetic overflow error converting varchar to data type numeric. --38 Digits after the decimal point and 1 non-zero before the decimal point.
SELECT CAST('000000000000000000000000000000000000001.0000000000000000000000000000000000000' as Decimal(8,4))--1.0000
--Caveats: When casting to an Integer:
SELECT CAST('3.0' as Int)--Conversion failed when converting the varchar value '3.0' to data type int.
--NOTE: When converting from character data to Int, you may want to do a double-conversion like so (if you want to Round your results first):
SELECT CAST(CAST('3.5' as Decimal(10)) as Int)--4. Decimal(10) has no decimal precision, so it rounds it to 4 for us BEFORE converting to an Int.
SELECT CAST(CAST('3.5' as Decimal(11,1)) as Int)--3. Decimal (11,1) HAS decimal precision, so it stays 3.5 before converting to an Int, which then truncates it.
--These are the best ways to go if you simply want to Truncate or Round.
SELECT CAST(CAST('3.99' as Decimal(10)) as Int)--3. Good Example of Rounding.
SELECT CAST(FLOOR('3.99') as Int)--3. Good Example fo Truncating.
The best solution would be to stop storing integers in a varchar column. Clearly there is a data issue where the data is interpretable as a numeric but cannot be cast as such. You need to find the record(s) that is(are) the problem and fix them if the data is such that it can and should be fixed. Depending on what you are storing and why it is a varchar to begin with, you may need to fix the query instead of the data. But that will be easier to do also if you first find the records which are blowing up your current query.
How to do that is the issue. It is relatively easy to search for a decimal place in the data to see if you have decimals (other than.0 which would convert) using charindex. You could also look for any record containing e or $ or any other character that could be interpeted as numeric according to the sources already given. If you don't have a lot of records a quick visual scan of the data will probably find it, especially if you sort on that field first.
Sometimes when I've been stuck on finding the bad data that is blowing up a query, I've put the data into a temp table and then tried processing in batches (using interpolation) until I find the one it blows up on. Start with the first 1000 (don't forget to use order by or you won't get the same results when you delete the good records and 1000 is only a best guess if you have millions of records start with a larger number). If it passes, delete those 1000 records and select the next batch. Once it fails, select a smaller batch. Once you are down to a number that can easily be visually scanned, you will find the problem. I've been able to find problem records fairly quickly when I have millions of records and a wierd error that none of the queries I've tried (which are basically guesses as to what might be wrong) have found the issue.
Try this and see if you still get an error...
SELECT CAST(CASE
WHEN IsNumeric(myVarcharColumn) = 0
THEN 0
ELSE myVarcharColumn
END AS BIGINT)
FROM myTable
WHERE IsNumeric(myVarcharColumn) = 1
AND myVarcharColumn IS NOT NULL
GROUP BY myVarcharColumn
ISNUMERIC is just... stupid. You shouln'd use it at all.
All cases bellow return 1:
ISNUMERIC('-')
ISNUMERIC('.')
ISNUMERIC('-$.')
For any integer types instead using: ISNUMERIC(#Value) = 1
just use: (#Value NOT LIKE '[^0-9]') OR (#Value NOT LIKE '-[^0-9]'
The only good solution is not to use ISNUMERIC.
Try wrapping it in a case:
select CASE WHEN IsNumeric(mycolumn) = 1 THEN CAST(mycolumn as bigint) END
FROM stack_table
WHERE IsNumeric(mycolumn) = 1
GROUP BY mycolumn
According to BOL ISNUMERIC returns 1 when the input expression evaluates to a valid numeric data type; otherwise it returns 0.
Valid numeric data types include the following:
int
numeric
bigint
money
smallint
smallmoney
tinyint
float
decimal
real
So as others pointed out you will have some data that will pass ISNUMERIC test but fail on casting to bigint
I had the same Issue and I came up with the Scalar Function as Im on 2008 SQL
ALTER Function [dbo].[IsInteger](#Value VarChar(18))
Returns Bit
As
Begin
Return IsNull(
(Select Case When CharIndex('.', #Value) > 0
Then 0
Else 1
End
Where IsNumeric(#Value + 'e0') = 1), 0)
End
If you are on 2012 you could use TRY_CONVERT
I had the same issue in MSSQL 2014 triggered by a comma instead of full stop:
isnumeric('9090,23') gives 1;
cast('9090,23' as float) fails
I've replaced ',' with '.'
there are DAX functions (IsError or IfError) that could help in this situation but we don't have those on our SQL Server 2008 R2. Looks like some additional analysis package for SQL Server.
I came across this blog post that might help. I've not run into this issue before and not sure if it'll help you in this instance:
http://dotmad.blogspot.com/2007/02/cannot-call-methods-on-bigint-error.html

Resources