How to default NULL to Zero - sql

I'm creating sprocs with some calculations and I want to make sure I'm not missing something simple.
Say I'm finding a SUM() of a column that might have NULLs. Is there a single set statement that will convert NULL to Zero automatically without having to COALESCE each time? Or do I have to manually check for NULL each time?
I've looked through MSDN SET but I don't see anything useful.
There's a way to make NULL work with concatenation but I don't see anything for calculations.
For example:
SET ANSI_NULLS ON
SET CONCAT_NULL_YIELDS_NULL ON
--Calc
SELECT SUM(CONVERT(decimal(10,2), NULL))
SELECT SUM(CONVERT(decimal(10,2), Coalesce(NULL,0)))
--Concat
SELECT NULL + ', ' + 'Isaak' AS Name
SELECT COALESCE(NULL + ', ' + 'Isaak','') AS Name
SELECT COALESCE(NULL,'') + ', ' + 'Isaak' AS Name
--Change Concat NULL to OFF
SET ANSI_NULLS ON
SET CONCAT_NULL_YIELDS_NULL OFF
--Calc
SELECT SUM(CONVERT(decimal(10,2), NULL))
SELECT SUM(CONVERT(decimal(10,2), Coalesce(NULL,0)))
--Concat
SELECT NULL + ', ' + 'Isaak' AS Name
SELECT COALESCE(NULL + ', ' + 'Isaak','') AS Name
SELECT COALESCE(NULL,'') + ', ' + 'Isaak' AS Name

No, there is no magic way to do this. However there are multiple workarounds:
Stop allowing NULLs in the first place - add a default of 0 and if you can't update the DML logic then add a trigger (but far preferable to do this as part of the original insert/update).
Put the COALESCE into a view, and then reference the view in your queries.
Persist a zero (using COALESCE of course) into a separate, computed column, and change the calculation to use the computed column instead of the original column.

Related

SQL - Search for WHERE clause with no spaces

I am trying to find a performance smart resolution to searching on data that is coming into an application with character spaces removed, but could exist in the DB system in many ways with spaces. I was thinking the following, but it seems to fail:
select top 1 * where REPLACE(Mfr, ' ', '') = #Mfr and REPLACE(Model, ' ', '') = #Model
Am I doing this completely wrong and is there a better way? It appears to time out only only a DB with 150k records at the moment.
You can implement the expressions as indexed virtual columns for fast lookup.
First you'll need to create the virtual columns:
alter table t add clean_mfr as replace(Mfr, ' ', '');
alter table t add clean_model as replace(Model, ' ', '');
Then you'll index them:
create index ix1 on t (clean_mfr, clean_model);
Now, you can try your query again. Since you are using equality (=) in both virtual columns lookups the query should be instantaneous.
Try:
select top 1 *
from t
where REPLACE(Mfr, ' ', '') = #Mfr and REPLACE(Model, ' ', '') = #Model
Or:
select top 1 *
from t
where clean_mfr = #Mfr and clean_model = #Model

Query Optimization -- I have a query that needs a 2nd set of eyes

I have inherited a query that seems to be a bit of a mess, or at least when I look at it I think that there must be a better way of doing it. The query:
select distinct 'INSERT INTO table1 SELECT '''+ACCT_NUM +''',* FROM table2 where library=''' + isnull(library,'') + '''' +
CASE
when CO is not NULL then ' and CO=''' +CO + ''''
else isnull(CO,'')
END +
CASE
when ACCTNO is not NULL then CASE WHEN LEN(acctNO)>5 then ' and ACCTNO=''' +ACCTNO + '''' else ' and ACCTNO like ''' +rtrim(ACCTNO) +'%'+ '''' END
else isnull(ACCTNO,'')
END +
CASE
when FILEDN is not NULL then ' and coalesce(nullif(PRMSTE,''''),ACCSTE)=''' +FILEDN + ''''
else isnull(FILEDN,'')
END +
CASE
when LOCNUM is not NULL then ' and LOCNUM=''' +LOCNUM + ''''
else isnull(LOCNUM,'')
END MySQL
INTO #temp
from table3
It generates a table of INSERT statements that are then looped through and executed via sp_executesql. Any help would be appreciated. I've been looking at this query now for over 2 months and I just can't seem to wrap my head around a better way of doing it.
Specifically I would like to see this taken down to one 'INSERT' statement or a 'SELECT ... INTO ...'
I think you need to completely throw this sql away and start from scratch.
Generating a table of insert statements and then executing them - really ?
Very very bad idea.
Insert the VALUES you need into a temporary table, not INSERT statements.
I would suggest doing some research on temporary tables - have a look at this article as a start: http://www.codeproject.com/Articles/42553/Quick-Overview-Temporary-Tables-in-SQL-Server

struggling with creating Insert query

I create Insert statement for organization table like this:
select'Insert into Organizations(Name,ContactPerson,ContactNumber,Mobilenumber)values('''+Nameofthecompany+''+','+Nameofthepersonresponsibleforrecruitment+','+PhoneNumber+','+MobileNumber+''')' from Organization
When I execute this statement I get insert statement. But the issue is where the value is null, it shows all columns null.
Example: (in database)
Name: xxxx
ContactPerson: zzzz
ContactNumber:444444
MobileNumber: null
so my insert statement looks like:
Null.
I want only that column provide null. other details showing properly. Is there any way in sql server? Help me anyone...
The result of concatenating anything to NULL, even itself, is always NULL. Workaround with ISNULL function:
select'Insert into Organizations(Name,ContactPerson,ContactNumber,Mobilenumber)
values('''+ISNULL(Nameofthecompany, 'NULL')+''+','
+ISNULL(Nameofthepersonresponsibleforrecruitment, 'NULL')+','
+ISNULL(PhoneNumber, 'NULL')+','
+ISNULL(MobileNumber, 'NULL')+''')'
from Organization
Demo on SQLFiddle
Sure - just use ISNULL(..) to turn a NULL into e.g. an empty string:
SELECT
'INSERT INTO Organizations(Name, ContactPerson, ContactNumber, Mobilenumber) VALUES(''' +
ISNULL(Nameofthecompany, '') + '' + ',' +
ISNULL(Nameofthepersonresponsibleforrecruitment, '') + ',' +
ISNULL(PhoneNumber, '') + ',' + ISNULL(MobileNumber,'') + ''')'
FROM Organization
When you are adding each of the parameters to the SQL statement, you need to check whether they're null, and if so use the keyword NULL, otherwise include a literal string surrounded with single quotes, but bearing in mind that if the string contains any single quotes, they need to be replaced with two single quotes.
Update the SQL for each parameter something like the following:
CASE WHEN MobileNumber IS NULL THEN 'NULL' ELSE '''' + REPLACE(MobileNumber, '''', '''''') + '''' END

Is there a better way to apply isnull to all columns than what I'm doing?

A number of times over the last month I've had to replace 'null' fields with '0' to every column returned from a query.
to save a lot of time (some of these are returning a high number of columns) I've been using the following and then pasting the results for relevant columns into a new query:
select ', isnull(' + COLUMN_NAME + ', 0)' + ' as ' + COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'summary_by_scca_sales_category '
and TABLE_SCHEMA = 'property''
Essentially I'm wondering if there's a better way that I can do this? Ideally a method where I could automatically apply isnull to all columns being returned in a query (without using two queries).
For example:
I want to take a query like:
select *
from tablename
And for every column returned by * replace null results with 0 without having to write an isnull() line for each column.
edit:
Will accomplish this with a view (doh, should have thought of that). For interests / educations sake is there a way to do something like this with code also?
You could create a VIEW against the tables in question where the ISNULL logic you want is set up. Then queries against the views would return the data you want.
EDIT:
As requested, some sample code to accomplish creating the VIEWs automatically. This is pretty gross, but for something that only has to be run once it will work. Beware of type issues (you stated everything should transmute to 0 so I assume all your columns are of a suitable numeric type):
DECLARE #table_def varchar(max)
SET #table_def = 'CREATE VIEW <tname>_NoNull AS SELECT '
SELECT #table_def = REPLACE(#table_def, '<tname>', t.name) +
'ISNULL(' + c.name + ', 0) AS ' + c.name + ', '
FROM sys.tables t
INNER JOIN sys.columns c ON t.object_id = c.object_id
WHERE t.name = <<table name>>
SELECT #table_def

LTRIM usage with SQL server 2005

I am a bit of an sql noob so please forgive. I can't seem to find a usage example of LTRIM anywhere.
I have a NVARCHAR column in my table in which a number of entries have leading whitespace - I'm presuming if I run this it should do the trick:
SELECT LTRIM( ColumnName)
From TableName;
Will this give the desired result?
No, it will trim leading spaces but not all white space (e.g. carriage returns).
Edit
It seems you are looking for an UPDATE query that will remove leading and trailing whitespace.
If by that you only mean "normal" spaces just use
UPDATE TableName
SET ColumnName = LTRIM(RTRIM(ColumnName ))
For all white space this should do it (from the comments here). Backup your data first!
UPDATE TableName
SET ColumnName =
SUBSTRING(
ColumnName,
PATINDEX('%[^ ' + char(09) + char(10) + char(13) + char(20) + ']%',
ColumnName),
LEN(ColumnName) - PATINDEX('%[^ ' + char(09) + char(10) + char(13) + char(20) + ']%'
, ColumnName) -
PATINDEX('%[^ ' + char(09) + char(10) + char(13) + char(20) + ']%',
REVERSE(ColumnName)) + 2)
Your example will work to remove the leading spaces. This will only select it from the database. IF you need to actually change the data in your table, you will need to write an UPDATE statement something like:
UPDATE TableName
SET ColumnName = LTRIM(ColumnName)
If you need to remove spaces from the right side, you can use RTRIM.
Here is a list of the string functions in SQL Server 2005 that I always refer to:
http://msdn.microsoft.com/en-us/library/ms181984(v=SQL.90).aspx
Did you run it to find out? It's just a select, it won't blow up your database. But, yes.
Select LTRIM(myColumn) myColumn
From myTable
Should return the myColumn values with any leading whitespace removed. Note this is only leading whitespace.
EDIT To Update the column, with the above, you'd do:
Update myTable
Set myColumn = LTRIM(myColumn)
From myTable