I have a table with a column Quantity; in the original table this column is defined as nvarchar(100) so I need to cast it as float to be able to do some analysis:
CAST([Quantity] AS FLOAT) AS Quantity
The issue is that I have some values which can not be converted to float like No-Quantity, Return etc. I to have filter to exclude these values and then convert rest to float.On option is use where clause:
WHERE Quantity IN ('Return', 'Sales')
This is not the best way since if we have anew values in the original table then I need to figure out what it is and add it to the where clause.
I am wondering is there is better way to identify non-convertible values?
If your SQL Server supports TRY_CONVERT, this could provide a nice solution:
SELECT TRY_CONVERT (float, [Quantity]) ...
will give you the converted values or NULL depending on the input. This could be helpful if you don't have strict control over the data.
In any database, you can use cast() and something like this:
(case when quantity not in ('No-Quantity', 'Return', . . .)
then CAST([Quantity] as float)
end) as Quantity
The in list would be the list of known string values.
You can also do a fast-and-dirty check like this:
(case when left(quantity, 1) between '0' and '1'
then CAST([Quantity] as float)
end) as Quantity
(Note: you may need to use substr() or substring() instead of left().)
And, in general, any specific database has specific functions that can help with the conversion, such as try_convert() mentioned in a comment.
Another way (if you can't use TRY_CONVERT)
SELECT CAST(quantity AS float)
FROM myTable
WHERE IsNumeric(quantity) = 1 AND quantity IS NOT NULL
Related
I'm a B-grade SQL user, so bear with me. I have a field that is in the NVARCHAR format ("Year"), but all but only about 1 in 1000 records is something other than a number. Yes, this is a ridiculous way to do this, but we receive this database from a customer, and we can't change it.
I want to pull records from the database where the year field is greater than something (say, 2006 or later). I can ignore any record whose year doesn't evaluate to an actual year. We are using SQL server 2014.
I have created an embedded query to convert the data to a "float" field, but for whatever reason, I can't add a where clause with this new floating-point field. I originally tried using a "case-if" but I got the same result.
I'm pulling my hair out, as I'm either missing something really silly, or there's a bug in SQL server. When I look at the field in the little hint, it's showing as a float. When I run this, I get "Error converting data type nvarchar to float."
SELECT VL.Field_A,
VL.FLYear,
VL.Field_B
FROM
(select
Field_A,
cast ([Year] as float) as FLYear,
/* didn't work either*/
/*Convert(float, [Year]) as FLYear, */
Field_B
from CustomerProvidedDatabaseTable
where (Field_A like 'E-%' OR
Field_A like 'F-%')
and
(isnumeric(year)=1)
and
year is not null
) VL
/* this statement is the one it chokes on */
where
VL.FLYear >= 2006.0
If I remove the last "where" clause, it works fine, and the field looks like a number. If I change the last where clause to:
where VL.FLYear like '%2006%'
SQL Server accepts it, though of course it doesn't return me all the records I want.
Try to simplify it and just use TRY_CONVERT(DATETIME, aYearvalue) or TRY_PARSE which will return NULL for values it can't convert and continue to process valid rows. I think you can do away with the where clause as join and just work directly against the column like: (substitute the literal string after datetime with your column)
SET DATEFORMAT mdy;
Select YEAR(try_convert(datetime, '08/01/2017')) as value1
WHERE value1 >=2016;
Try cast/convert to a numeric data type. I have modified the last line of your query to do just that. Take a peek.
SELECT
VL.Field_A,
VL.FLYear,
VL.Field_B
FROM
(select
Field_A,
cast ([Year] as float) as FLYear,
/* didn't work either*/
/*Convert(float, [Year]) as FLYear, */
Field_B
from CustomerProvidedDatabaseTable
where (Field_A like 'E-%' OR
Field_A like 'F-%')
and
(isnumeric(year)=1)
and
year is not null
) VL
/* this statement is the one it chokes on */
where
ISNUMERIC(VL.FLYear) = 1
and
CAST(VL.FLYear AS INT) >= 2006
Check out the following link for cast and convert documentation:
https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql
NOTE: ISNUMERIC will return true ( a false positive for a value which has a scientific numerical value, e.g. 1E10, though I don't see this happening from your data).
Another option is TRY_CONVERT.
Documentation on TRY_CONVERT: https://learn.microsoft.com/en-us/sql/t-sql/functions/try-convert-transact-sql
Try using Cast . Use the below link to check in more detail about casting.
https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql
I have sql query (Eg. select amount from purchase_order) which outputs something like 123.45. Instead I want it output it like 123,45 (German numeral system). How do I do that?
Use the REPLACE function
SELECT REPLACE(amount, '.',',') FROM purchase_order
Keep in mind that this will replace all values that match, so in this case all periods would be replaced with commas
Use the replace function (Convert to char beforehand,if necessary). Example:
REPLACE ( TO_CHAR(amount), '.', ',')`.
Even better: set your locale properly. Thereafter all number lexicalisations should follow the respective convention.
There may also be the option to decide on a case-by-case basis. Example (Oracle syntax; you specify 2 characters, the decimal point and the group separator. For German, this would be ,., for English .,, resp.):
TO_CHAR ( amount, '9999D99', 'NLS_NUMERIC_CHARACTERS='',.''' )
use stuff string function to replae the(.) by (,)
select stuff(amount ,charindex('.', amount),1,',')
from purchase_order
"needs to be done on the db side because there are calculations involved after this"
Then don't worry about the format. In the database it's just a number. Any calculations will apply to the number itself regardless of how it's observed. Formatting only gets applied when you view the number. Don't do any formatting prior to calculations.
Do formatting at the very last layer - the UI/reporting layer.
With SQL Server 2012, you have the FORMAT function.
There is no need to do this on the db side even if calculations are involved after this...
So try this :
SQL Fiddle
MS SQL Server 2012 Schema Setup:
CREATE TABLE purchase_order
([amount] money)
;
INSERT INTO purchase_order
([amount])
VALUES
(123.45)
;
Query 1:
select FORMAT ( amount, 'G', 'de-de' ) AS 'amount'
from purchase_order
Results:
| AMOUNT |
|----------|
| 123,4500 |
I have a NUMERIC(5, 0) field in a IBM db2 database from which I only want the first 4 digit. I haven't been able to achieve what I want with using CAST.
How can I achieve this in SQL without casting as a String and using substring ?
Ex: 13525 --> 1352
Thanks for your help!
Why not cast as a string and use substring?
You can also do:
select (case when field >= 10000 then floor(field / 10) else field end)
This assuming that if the field has 1234, then you want 1234 rather than 0123.
EDIT:
You can also use a string by using two calls to cast():
select cast(left(cast(field as varchar(5)), 4) as numeric(4, 0))
I should also note that in many databases, you can just do:
select left(field, 4)
and the database will do the appropriate conversions. I don't have DB2 nearby to check this.
I'm trying to convert a number to a decimal with two decimals places.
SELECT CONVERT(DECIMAL(10,2),12345)
The above would return 12345.00 but I'm trying to achieve 123.45
You need something like that:
SELECT CONVERT(DECIMAL(15,2),12345/100.0)
SELECT CONVERT(DECIMAL(10,2),CAST(12345 as float)/CAST(100 as float))
Correction: The premise is somewhat flawed, as the data type of a literal number without a decimal point is int, not numeric as implied by the question. In that case, you do need to convert the initial value to either numeric or decimal before dividing:
SELECT CONVERT(DECIMAL,12345)/100
or
SELECT CAST(12345 AS DECIMAL)/100
(cast is the SQL standard, so if you ever want to apply this to other databases, it would be the preferred method.)
Alternately, you can just add a decimal point to the divisor, as SQL server will return the more precise data type when doing arithmetic on heterogeneous types:
SELECT 12345/100.0
According to the documentation, the numeric data type is functionally equivalent to the decimal datatype, so there's really no reason to convert between the two. It seems that all you really want to do is divide the value you have by 100:
SELECT 12345/100
I have a table that has non-numeric values in the source.
I am using a CTE to filter down to a set of values that is all numeric.
However, when I try to convert the filtered list to float, I get an error.
Goal is to find all Lab Results that are less than 8.0
CTE:
;with labs AS (
SELECT LabResult_Result
FROM VIEW_PatientLabResult
WHERE (LabResult_DateTimeOfObservation between '1/1/2012' and '1/1/2013') and
MasterLabCode_Description='Hemoglobin (Hgb) A1c'
)
Results in ~250 rows, all of which are decimal (manually checked).
Cannot get to convert them to float for comparison. Best I have so far is:
select * from
(
select *, CAST( labresult_result as float) as Converted
FROM labs
) Conv
WHERE Conv.Converted < 8.0
This results in Error converting data type varchar to float.
Without the WHERE clause, the query runs fine.
I am thinking that SQL is trying to convert the entire results before the CTE filter. Is there a way to make it run in order?
SQL only guarantees the order of execution when you use a case statement. (Although as Aaron points out, this is not true for aggregated values in a group by expression.)
Try this instead:
select *
from (select *, (case when ISNUMERIC(labresult_result) = 1 then CAST(labresult_result as float)
end) as Converted
FROM labs
) conv
where conv.converted < 8.0
In the original query, SQL is free to rearrange the where clauses to optimize the query -- even between CTEs and subqueries. This can result in an unexpected error. Remember, SQL is a descriptive language that describes the output, not a procedural language that specifies how things are processed.