Force COALESE(NULL,NULL) to return NULL - sql

In SQL SERVER
Considering the fact that:
Col1 and Col2 contain numeric and NULL values
SELECT
COALESCE(Col1,Col2)
Return an error: "At least one of the arguments to COALESCE must be an expression that is not the NULL constant."
Considering that Col1 and Col2 are NULL,I want to force it to return NULL value in this case.
The workaround seems to be unelegant/inefficient for me:
SELECT
NULLIF(COALESCE(Col1 ,Col2 ,''),'')
Note that Col1 and Col2 are numeric fields and cannot take '' as a value.
Any other suggestion ?
Thank you for your help

This code works:
SELECT COALESCE(Col1, Col2)
FROM . . . -- references here that define COL1 and COL2
If both columns are NULL, it will return NULL (typed as an integer in your case).
The only time you get the error you mention is when the columns are explicitly NULL. Even calculations seem to get around this:
select coalesce(null + 3, null)
--> NULL rather than an error
The following even returns NULL rather than an error:
declare #col1 int;
declare #col2 int;
select coalesce(#col1, #col2);
Here is a db<>fiddle.

Related

SQL not NULL(no default value) but allowed to insert NULL value

I have this table nonulls col1 varchar NULL col2 numeric (24,6) NOT NULL.
How can I insert value like this,
INSERT INTO nonulls (col1) SELECT 'ARF' as col1
Without having value for col2, some existing command in some of SSIS package here have that kind like of query but the col2 is not null but it still proceeds inserting value. Without using "coalesce" and without changing NOT NULL to "allow null".
If col2 has a default value, then you can insert a row with no value. It would be declared something like:
col2 <type> not null default <default value>
The default default value is NULL, which a not null declaration would preclude.
It is also possible that the table has an insert trigger defined on it. The trigger could assign a value to the column.

MSSQL Server 2008 - Convert Nvarchar to numeric

im using mssql 2008 and Im permanently failing to convert an nvarchar to numeric values.
Can you please advise? I have different solutions I found over the www, but all of them are failing with the error message:
Msg 8114, Level 16, State 5, Line 15 Error converting data type
nvarchar to numeric.
I have built an reduced example for demonstration purpose:
IF OBJECT_ID('tempdb..#temptable', 'U') IS NOT NULL
DROP TABLE dbo.#temptable
create table #temptable(
col1 nvarchar(10),
col2 numeric(10,5)
)
insert into #temptable values ('0,5','0')
select *,convert(numeric(18,2),col1) from #temptable
UPDATE #temptable
SET col2 = CAST(col1 AS numeric(10,5))
WHERE ISNUMERIC(col1) = 1
SELECT col1
, CASE ISNUMERIC(col1)
WHEN 1 THEN CONVERT(numeric(18,2),col1)
ELSE 0.00
END
from #temptable
I alreay found an strong hint whats going wrong... the issue seems to be related to the , as seperator while the SQL server expects an .
if you change the following line to:
insert into #temptable values ('0.5','0')
its working
The problem is you are using ISNUMERIC(col1) = 1 which fails for a ton of cases like ISNUMERIC('1e4') or ISNUMERIC('$') or in your case, ISNUMERIC('1,000,000'). Don't use ISNUMERIC in this fashion.
Instead, try this...
UPDATE #temptable
SET col2 = CAST(col1 AS numeric(10,5))
WHERE col1 not like '%[^0-9.]%'
Use try_convert() in SQL Server 2012+:
UPDATE #temptable
SET col2 = TRY_CONVERT(numeric(10,5), col1)
WHERE ISNUMERIC(col1) = 1;
SQL Server re-arranges expression valuation in a query. So, the CAST() might be implemented before the WHERE -- resulting in the error. You can make a similar change to the SELECT version of your query.
In SQL Server 2008, you should be able to do effectively the same thing using CASE:
UPDATE #temptable
SET col2 = (CASE WHEN ISNUMERIC(col1) = 1 THEN CONVERT(numeric(10, 5), col1) END)
WHERE ISNUMERIC(col1) = 1;
Note: There may be cases where ISNUMERIC() returns "1", but the value cannot be converted (for instance, overflow). In that case, this version would still fail.

SQL Server - Convert String to float with N/A's present

I have a flat file that I loaded into SQL Server using the import wizard. All columns are stored as nchar(50).
I'm now trying to convert the table to a new table with various types (char, float, int, etc).
There is one column that I'd like to convert to float but it contains N/A strings.
I checked that there weren't any other weird string using this:
SELECT col1, count(*)
from tab1
where ISNUMERIC(col1) <> 1
group by col1
Then I wrote a CASE statement to do the conversion:
SELECT CASE WHEN col1 = 'N/A' THEN NULL ELSE CAST(col1 AS FLOAT) END col1
INTO tab2
FROM tab1
But I'm getting this error message:
Msg 8114, Level 16, State 5, Line 1
Error converting data type nvarchar to float.
Any idea what's causing this?
If 2012+ Use try_convert()
SELECT col1, count(*)
from tab1
where try_convert(float,col1) is null
group by col1
You can use try_convert if you want to ignore invalid chars to float as below
Select try_convert(float, col1) as col1 from yourtable
Careful on using ISNUMERIC() for this. It can return some false positives. For example...
select isnumeric('$')
select isnumeric('1e4')
This should show you what is causing the error.
select * from table where column like '%[^0-9\.]%' escape '\'
You can use this in a where clause, or use TRY_CONVERT()
You aren't doing the type conversion from the String to the float. In your SQL statements you need to explicitly cast the original column type from nvarchar to float. Something like this might work:
SELECT
CASE
WHEN col1 = 'N/A' THEN NULL
ELSE CAST(col1 AS FLOAT)
END col1
INTO tab2
FROM tab1

Oracle/PL SQL/SQL null comparison on where clause

Just a question about dealing will null values in a query.
For example I have the following table with the following fields and values
TABLEX
Column1
1
2
3
4
5
---------
Column2
null
A
B
C
null
I'm passing a variableY on a specific procedure. Inside the procedure is a cursor like this
CURSOR c_results IS
SELECT * FROM TABLEX where column2 = variableY
now the problem is variableY can be either null, A, B or C
if the variableY is null i want to select all record where column2 is null, else where column2 is either A, B or C.
I cannot do the above cursor/query because if variableY is null it won't work because the comparison should be
CURSOR c_results IS
SELECT * FROM TABLEX where column2 IS NULL
What cursor/query should I use that will accomodate either null or string variable.
Sorry if my question is a bit confusing. I'm not that good in explaining things. Thanks in advance.
Either produce different SQL depending on the contents of that parameter, or alter your SQL like this:
WHERE (column2 = variableY) OR (variableY IS NULL AND column2 IS NULL)
Oracle's Ask Tom says:
where decode( col1, col2, 1, 0 ) = 0 -- finds differences
or
where decode( col1, col2, 1, 0 ) = 1 -- finds sameness - even if both NULL
Safely Comparing NULL Columns as Equal
You could use something like:
SELECT * FROM TABLEX WHERE COALESCE(column2, '') = COALESCE(variableY, '')
(COALESCE takes the first non NULL value)
Note this will only work when you the column content cannot be '' (empty string). Else this statement will fail because NULL will match '' (empty string).
(edit)
You could also consider:
SELECT * FROM TABLEX WHERE COALESCE(column2, 'a string that never occurs') = COALESCE(variableY, 'a string that never occurs')
This will fix the '' fail hypothesis.
Below is similar to "top" answer but more concise:
WHERE ((column2 = variableY ) or COALESCE( column2, variableY) IS NULL)
May not be appropriate depending on the data you're looking at, but one trick I've seen (and used) is to compare NVL(fieldname,somenonexistentvalue).
For example, if AGE is an optional column, you could use:
if nvl(table1.AGE,-1) = nvl(table2.AGE,-1)
This relies on there being a value that you know will never be allowed. Age is a good example, salary, sequence numbers, and other numerics that can't be negative. Strings may be trickier of course - you may say that you'll never have anyone named 'xyzzymaryhadalittlelamb" or something like that, but the day you run with that assumption you KNOW they'll hire someone with that name!!
All that said: "where a = b or (a is null and b is null)" is the traditional way to solve it. Which is unfortunate, as even experienced programmers forget that part of it sometimes.
Try using the ISNULL() function. you can check if the variable is null and if so, set a default return value. camparing null to null is not really possible. remember: null <> null
WHERE variableY is null or column2 = variableY
for example:
create table t_abc (
id number(19) not null,
name varchar(20)
);
insert into t_abc(id, name) values (1, 'name');
insert into t_abc(id, name) values (2, null);
commit;
select * from t_abc where null is null or name = null;
--get all records
select * from t_abc where 'name' is null or name = 'name';
--get one record with name = 'name'
You could use DUMP:
SELECT *
FROM TABLEX
WHERE DUMP(column2) = DUMP(variableY);
DBFiddle Demo
Warning: This is not SARG-able expression so there will be no index usage.
With this approach you don't need to search for value that won't exists in your data (like NVL/COALESCE).

Referring to column values directly without using variables in T-SQL

Is there a way in T-SQL (SQL Server 2005) to assign a whole record to a record variable and then refer to the particular values using column names?
I mean, instead of:
select #var1 = col1,
#var2 = col2
from mytable
where ID = 1;
and referring to them as #var1 and #var2, something like
#record =
select col1, col2
from mytable
where ID = 1;
and referring to them like #record.col1 and #record.col2 .
I am beginner in t-sql, so hopefully the question is not too trivial.
You can create a table variable and select the whole resultset into it:
DECLARE #tt TABLE (col1 INT, col2 INT)
INSERT
INTO #tt
SELECT col1, col2
FROM mytable
WHERE id = 1
, but you cannot access its data except than in the SELECT query as well.
With pure TSQL (that it without custom datatypes) the thing you ask is impossible.
sounds like you are a programmer ... look at linq maybe as it does what you want.
You can use a temporary table and SELECT...INTO to avoid specifying the column names at the beginning :
SELECT Field1, Field2
INTO #TempTable
FROM MyTable
WHERE MyTable.MyID = 1
but of course you'll still need the FROM #TempTable part when referring to the column names.
SELECT Field1, Field2
FROM #TempTable
and of course to remember to drop the table at the end :
DROP #TempTable
The app code is where you'd normally refer to a single row at a time as a variable.
You could use XML, but you'd have to play with this...
DECLARE #MyRecord xml
DECLARE #Mytable TABLE (col1 int NOT NULL, col2 varchar(30) NOT NULL)
INSERT #Mytable (col1, col2) VALUES (1, 'bob')
select #MyRecord =
(SELECT *
from #Mytable
where col1 = 1
FOR XML AUTO)
SELECT #myRecord.value('./#col', 'int') --also #myRecord.value('#col', 'int')
--gives error
Msg 2390, Level 16, State 1, Line 12
XQuery [value()]: Top-level attribute nodes are not supported
Buried in the Transact SQL documentation I came across this restriction on variables:
Variables can be used only in expressions, not in place of object names or keywords.
Since you'd need to use an object name to qualify a column I don't believe that this is allowed.