Cast string to number, interpreting null or empty string as 0 - sql

I have a Postgres table with a string column carrying numeric values. I need to convert these strings to numbers for math, but I need both NULL values as well as empty strings to be interpreted as 0.
I can convert empty strings into null values:
# select nullif('','');
nullif
--------
(1 row)
And I can convert null values into a 0:
# select coalesce(NULL,0);
coalesce
----------
0
(1 row)
And I can convert strings into numbers:
# select cast('3' as float);
float8
--------
3
(1 row)
But when I try to combine these techniques, I get errors:
# select cast( nullif( coalesce('',0), '') as float);
ERROR: invalid input syntax for integer: ""
LINE 1: select cast( nullif( coalesce('',0), '') as float);
# select coalesce(nullif('3',''),4) as hi;
ERROR: COALESCE types text and integer cannot be matched
LINE 1: select coalesce(nullif('3',''),4) as hi;
What am I doing wrong?

The types of values need to be consistent; coalescing the empty string to a 0 means that you cannot then compare it to null in the nullif. So either of these works:
# create table tests (orig varchar);
CREATE TABLE
# insert into tests (orig) values ('1'), (''), (NULL), ('0');
INSERT 0 4
# select orig, cast(coalesce(nullif(orig,''),'0') as float) as result from tests;
orig | result
------+--------
1 | 1
| 0
| 0
0 | 0
(4 rows)
# select orig, coalesce(cast(nullif(orig,'') as float),0) as result from tests;
orig | result
------+--------
1 | 1
| 0
| 0
0 | 0
(4 rows)

You could also use
cast(
case
when coalesce(orig, '') = '' then '0'
else orig
end
as float
)
You could also unwrap that a bit since you're being fairly verbose anyway:
cast(
case
when orig is null then '0'
when orig = '' then '0'
else orig
end
as float
)
or you could put the cast inside the CASE:
case
when coalesce(orig, '') = '' then 0.0
else cast(orig as float)
end
A CASE makes it a bit easier to account for any other special conditions, this also seems like a clearer expression of the logic IMO. OTOH, personal taste and all that.

Actually, you can cast NULL to int, you just can't cast an empty string to int. Assuming you want NULL in the new column if data1 contains an empty string or NULL, you can do something like this:
UPDATE table SET data2 = cast(nullif(data1, '') AS int);
or
UPDATE table SET data2 = nullif(data1, '')::int;
Reference

Check if you query parameter is empty (accepts null, empty string or value):
SELECT CAST(TO_JSON(NULLIF(:myParameter, NULL)) AS VARCHAR) IS NULL OR
CAST(TO_JSON(NULLIF(:myParameter, NULL)) AS VARCHAR) IN ('""');

Related

Concatenation, rounding, and dealing with nulls

I have the following table:
x y
1 1
1 0
1 null
0 1
0 0
0 null
null 1
null 0
null null
And I want to produce the following column:
z
11
10
1null
01
00
0null
null1
null0
nullnull
But I'm having difficulty dealing with the rounding that occurs when using coalesce to convert potential null values to 'null'. Trying this:
select concat(cast(coalesce(x, 'null') as int), cast(coalesce(y, 'null') as int))
Gives me the error Numeric value 'null' is not recognized. Even a simple select concat(cast(x as char), cast(y as char)) doesn't produce the desired results, although no error occurs.
Technically, the following works (using REGEXP_REPLACE). But this seems a bit hacky. Is there a better documented way of doing this?
select
regexp_replace(concat(case when x is null then 'null' else x end, case when y is null then 'null' else y end), '\.[0]+', '')
Your value are strings, not ints. So, convert them to the right type:
select concat(coalesce(cast(x as varchar(255)), 'null'),
coalesce(cast(y as varchar(255)), 'null')
)
Note: Not all databases support varchar(255) in this context and need something like string or char.

Cast substring to int only for numeric values in SQL

I have this query :
SUBSTRING (
dbo.Table.RNumber,
1,
CHARINDEX(
'+',
dbo.Table.RNumber
) - 1
) AS RoomNumber,
SUBSTRING (
dbo.Table.R.Number,
CHARINDEX(
'+',
dbo.Table.R.Number
) + 1,
LEN(
dbo.Table.R.Number
)
) AS HallNumber,
My Table RNumber is mostly like 2+3 or 3+5, but sometimes it is like x+5 or y+0. I want to convert fields to int, but I want to convert strings like "x" or "y" to 0. I googled it but I couldn't find a solution. How can I do that? Thanks.
You can use case statement try this
Edited to use isnumeric() method
CASE
WHEN isnumeric(SUBSTRING(dbo.Table.RNumber,1,CHARINDEX('+',dbo.Table.RNumber) - 1)) = 1
THEN SUBSTRING(dbo.Table.RNumber,1,CHARINDEX('+',dbo.Table.RNumber) - 1)
else 0
end AS RoomNumber,
CASE
WHEN isnumeric(SUBSTRING(dbo.Table.R.Number,CHARINDEX('+',dbo.Table.RNumber) + 1,LEN(dbo.Table.R.Number))) = 1
THEN SUBSTRING(dbo.Table.R.Number,CHARINDEX('+',dbo.Table.RNumber) + 1,LEN(dbo.Table.R.Number))
else 0
end AS HallNumber,
Hope this should solve your problem
Perhaps you can use ParseName() and Try_Convert()
Declare #YourTable table (SomeField varchar(50))
Insert Into #YourTable values
('2+3'),('3+5'),('x+5'),('y+0')
Select *
,RoomNumber = IsNull(Try_Convert(int,ParseName(Replace(SomeField,'+','.'),2)),0)
,HallNumber = IsNull(Try_Convert(int,ParseName(Replace(SomeField,'+','.'),1)),0)
From #YourTable
Returns
SomeField RoomNumber HallNumber
2+3 2 3
3+5 3 5
x+5 0 5
y+0 0 0
For versions prior to 2012, you can do it like this:
CASE
WHEN NOT columnName like '%[^0-9]%' -- Contains no non-digits
AND columnName like '%[0-9]%' -- contains at least one digit
THEN CAST(columnName as INT) ELSE NULL
END
(Note that this will reject negative numbers, but you can easily adapt it if you need to support them)
Alternatively using IsNumeric, you must first cast to float because Isnumeric accepts some strings that Cast(EXPRESSION as INT) does not accept:
CASE WHEN ISNUMERIC(columnName)=1
THEN CAST(CAST(columnName as float) as int) END

trim sql variant

I have column sql variant, which has the following meanings: 100, 150, D1
I'm trying to convert all numbers in the columns into letters (such as D1) according to specific logic in case when. But 150 has spaces and the CASE WHEN doesn't work.
Here's the query I'm using:
Select *,
Case When LTrim(Cast(AttributeValue As NVarchar(Max))) Between 0 And 200 Then 'D1'
Else 'Other'
End
From MyTable As SCR With (NoLock);
I tried the following
LTRIM(CAST column AS VARCHAR(MAX))
but now I get error:
Conversion failed when converting the nvarchar value 'D1' to data type int
How can I remove spaces from sql_variant?
As per your comments edited to use BIGINT due to having larger numbers and leave the column the same if it is not BETWEEN 0 and 400
SELECT *
,CASE
WHEN ISNUMERIC(LTRIM(CAST(AttributeValue AS NVARCHAR(MAX)))) = 1
AND CAST(LTRIM(CAST(AttributeValue AS NVARCHAR(MAX))) AS BIGINT) BETWEEN 0 AND 400 THEN 'D1'
ELSE AttributeValue
END
FROM
MyTable AS SCR WITH (NOLOCK)
You can use the ISNUMERIC() function to determine which of your sql_variants are integers and which are not.
The reason your code is failing isn't because of the trim it is because you are comparing a VARCHAR with an INTEGER so SQL is trying to automatically re cast your final string as an integer which in the case of D1 is not numeric so it causes a conversion error.
Also note that you cannot use sql_variant directly in the ISNUMERIC() function so cast to a varchar first.
Here is an entire example of you to show you how it works:
DECLARE #MyTable AS TABLE (AttributeValue SQL_VARIANT)
INSERT INTO #MyTable VALUES
(CAST(' 150' AS VARCHAR(100)))
,(CAST('D1' AS VARCHAR(100)))
SELECT *
,CASE
WHEN ISNUMERIC(LTRIM(CAST(AttributeValue AS NVARCHAR(MAX)))) = 1
AND CAST(LTRIM(CAST(AttributeValue AS NVARCHAR(MAX))) AS INT) BETWEEN 0 AND 200 THEN 'D1'
ELSE 'Other'
END
FROM
#MyTable AS SCR
use sql replace function
select replace(columnnName, ' ', '')

Varchar to Decimal conversion in DB2 with empty and null values

I have a varchar field AMOUNT in DB2.
Possible table state values:
ID AMOUNT
-------------------------
1 123.4578
2 NULL
2 123.78
1 -8562.85441
2
1 0.0
-------------------------
Column AMOUNT can be empty as the second last row above depicts.
I want to do a SUM over the AMOUNT group by ID in a query.
The result SUM should be DECIMAL(16,2).
What will be the correct way to do that considering that the value can be both null and empty and also the number of digits after the decimal is not following any fixed format?
It's a duplicate of this question, but the answers given are not complete and not accepted.
Thanks for reading!
I think the code you want is:
select (case when amount <> '' then cast(amount as float) end)
from table t;
You don't have to worry about NULL values. sum() ignores them. If you want to get 0 if all values are NULL/blank, then add else 0 to the case statement.
If you are concerned about other non-numeric values, you can try:
select (case when amount <> '' and
not regexp_like(amount, '[^0-9.]', '')
then cast(amount as float) end
from table t;
CAST(CASE WHEN ISNULL(AMOUNT, '') = '' THEN NULL ELSE REPLACE(AMOUNT, ',', '.') END AS DECIMAL (16,2)) AS AMOUNT
or
CAST (123.4578 AS DECIMAL (16,2))
+ CAST (NULL AS DECIMAL (16,2))
+ CAST (123.78 AS DECIMAL (16,2))
+ CAST (-8562.85441 AS DECIMAL (16,2))
= RESULT DECIMAL(16,2)

SELECT * FROM col WHERE name != 'NULL' && name (is an int) - SQL PROBLEM

I have an sql statement which I now need to change so it only returns values back that are integers.
SELECT * FROM col WHERE name != 'NULL' <-- this works
But now I need to extend that to something like:
SELECT * FROM col WHERE name != 'NULL' && name (is an int)
But I cannot figure out the sql for this. Does anyone have any ideas?
SQL:
SELECT * FROM col WHERE NOT name IS NOT NULL AND name NOT LIKE '%[^0-9]%'
or
SELECT * FROM col WHERE NOT name IS NOT NULL AND ISNUMERIC(name) = 1
Warning, ISNUMERIC can return 1 for some non numeric characters such as +, -, or $
Here is some more information on ISNUMERIC
Also, when comparing against NULL in SQL you must use IS NULL or IS NOT NULL
For SQL server this is the Syntax:
SELECT * FROM col WHERE NOT name IS NULL AND ISNUMERIC(name) = 1 AND NOT name LIKE '%.%'
Assuming "." is used for decimals
If you use MSSQL,
SELECT * FROM col WHERE name <> 'NULL' AND IsNumeric(name) = 1