SQL Question checking nulls - sql

I'm very new to sql. I am on this project where I have to check if something is null and if it is I have to change it to zero but there are many tables that I would have to do this and many columns. I was wondering if there was a way that I can check the whole table for nulls instead of checking every column of every table.

Michelle, no you need to check every column for NULLS. The bigger question is why are NULLS being allowed? While I'm not an advocate for never having NULLS in a database (I believe that they have their purpose), an excessive number of NULL values in a table is a good indicator that the database is not normalized properly or has other architectural issues.

It does depend on the platform, but in some cases you can use the system table information to get a list of all of the columns, and utilise this to generate queries to verify every column in every table.
However, that would be quite a hack. The real questions are a) why are there so many nulls ( there might be good reasons, but it does suggest that the structure is wrong, as per Wil ) and b) why is there a sudden need to change then all to zeros? Does this only apply to numeric fields? There are so many other questions that you need to ask before a clear solution becomes clear.

You say you have to change any NULL values to 0, so perhaps the easiest way would be to use COALESCE(value, 0).
COALESCE(value, value2, value3) is a shortcut to a CASE statement like
CASE
WHEN value1 IS NOT NULL THEN value1
WHEN value2 IS NOT NULL THEN value2
...
END
Edit:
If you actually want to update all NULLS to 0 on the table, you could do the following SQL statement:
SELECT 'UPDATE '
+ OBJECT_NAME(OBJECT_ID)
+ ' SET '
+ sc.name
+ ' = 0 WHERE '
+ sc.name
+ ' IS NULL'
FROM sys.columns sc
INNER JOIN sys.types st ON st.system_type_id = sc.system_type_id
WHERE st.name IN ('bigint', 'int', 'smallint')
AND OBJECT_NAME(OBJECT_ID) = 'YourTable'
Which will product a text string that you should be able to copy and paste and run, or run programatically in a loop. It depends on your columns having a number data type, and could be dangerous if you have any such columns whose NULLs you actually want to stay as null. You could take out that last part of the WHERE clause to run it for all tables, but you may want to test and validate beforehand.
I don't have a SQL Server instance at the ready to test on, so this comes with the generic "use at your own risk" disclaimer. :-)

Select nvl(col,'0') from table ;
NVL will work fine in oracle.
NVL will check if col is null, if it is null it will change it to zero.

Related

Replacing null values automatically for a specific set of tables in SQL Server

I would like to write a query that can update all values on any given table to this -- given that I have many columns across multiple tables the function needs to be universal meaning i can run it without specifying column names, for it simply to identify null values and update them with my value of -- I'm not sure the best way to accomplish this and wrap it into a function I can call when someone INSERTS into any of the tables affected.
I've looked at COALESE as a possible option but any examples would be appreciated.
My table looks like: (I have over 30 tables with 100+ fields so writing out Updates for each field individually sounds like a nightmare, there must be a better way)
ID Name Email Phone
1 John john#aol.com 234-234-2344
2 Mary mary#test.com 332-134-5424
3 Simon null null
4 Kevin null 345-453-2135
5 Kelly kelly#msn.com null
I'd like to replace all nulls with -- permanantly in my table probably using an UPDATE statement.
Any ideas appreciated.
Following SQL will help you to list down all the tables and column names. And you can build a dynamic SQL thingy around this result set to achieve what you want.
SELECT DISTINCT
--SCHEMA_NAME(schema_id) AS schema_name,
t.name AS TableName,
c.name AS ColumnName
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
ORDER BY 1,2;
EDIT:
Otherwise, the following link got a solution to your problem.
SQL Server Find and Replace Values in All Tables and All Text Columns
Umm, you are really overcomplicating this. I would suggest instead:
alter table t
alter column phone not null default '--';
Before doing this, update the column so there are no NULL values:
update t
set phone = '--'
where phone is null;
And, I should throw in that I think this is a bad idea. You are confusing "data" with "representation". In an application, you want to show -- for a NULL value. But I think NULL is the best way to represent the missing value in a database.
(And, of course, you need to do the above for each column you care about.)

PL/SQL Oracle condition equals

I think I'm encountering a fairly simple problem in PL/SQL on an Oracle Database(10g) and I'm hoping one of you guys can help me out.
I'm trying to explain this as clear as possible, but it's hard for me.
When I try to compare varchar2 values of 2 different tables to check if I need to create a new record or I can re-use the ID of the existing one, the DB (or I) compares these values in a wrong way. All is fine when both the field contain a value, this results in 'a' = 'a' which it understands. But when both fields are NULL (or '' which Oracle will turn into NULL) it can not compare the fields.
I found a 'solution' to this problem but I'm certain there is a better way.
rowTable1 ROWTABLE1%ROWTYPE;
iReUsableID INT;
SELECT * INTO rowTable1
FROM TABLE1
WHERE TABLE1ID = 'someID';
SELECT TABLE2ID INTO iReUsableID
FROM TABLE2
WHERE NVL(SOMEFIELDNAME,' ') = NVL(rowTable1.SOMEFIELDNAME,' ');
So NVL changes the null value to ' ' after which it will compare in the right way.
Thanks in advance,
Dennis
You can use LNNVL function (http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions078.htm) and reverse the condition:
SELECT TABLE2ID INTO iReUsableID
FROM TABLE2
WHERE LNNVL(SOMEFIELDNAME != rowTable1.SOMEFIELDNAME);
Your method is fine, unless one of the values could be a space. The "standard" way of doing the comparison is to explicitly compare to NULL:
WHERE col1 = col2 or col1 is null and col2 is null
In Oracle, comparisons on strings are encumbered by the fact that Oracle treats the empty string as NULL. This is a peculiarity of Oracle and not a problem in other databases.
In Oracle (or any RDBMS I believe), one NULL is not equal to another NULL. Therefore, you need to use the workaround that you have stated if you want to force 2 NULL values to be considered the same. Additionally, you might want to default NULL values to '' (empty) rather than ' ' (space).
From Wikipedia (originally the ISO spec, but I couldn't access it):
Since Null is not a member of any data domain, it is not considered a "value", but rather a marker (or placeholder) indicating the absence of value. Because of this, comparisons with Null can never result in either True or False, but always in a third logical result, Unknown.
As mentioned by Jan Spurny, you can use LNNVL for comparison. However, it would be wrong to say that a comparison is actually being made when both values being compared are NULL.
This is indeed a simple and usable way to compare nulls.
You cannot compare NULLS directly since NULL is not equal NULL.
You must provide your own logic who you would like to compare, what you've done with NVL().
Take in mind, you are treating NULLS as space, so ' ' in one table would be equal to NULL in another table in your case.
There are some other ways (e.g. LNNVL ) but they are not some kind of a "better" way, I think.

SQL to find the names of all columns in a table where the SUM of the column is greater than zero

I have a table in SQL Sever 2005 where many of the columns contain only NULL or 0 or 0.0.
I want a query to find the names of every column in that table that have a SUM greater than 0 i.e. the table contains at least one row where its value is not null and is greater than zero.
Thanks.
Simplest I believe would be to take the output of following statement and run it as a script.
SELECT SELECT COUNT(*), ''' + name + ''' FROM dbo.ATable WHERE ' + name + '> 0'
FROM sys.columns sc
WHERE OBJECT_NAME(OBJECT_ID) = 'ATable'
I don't know the system tables off hand but you can exclude anything not being a number by looking at the types of the individual columns. If I'm not mistaken, you could join with sys.types
If you need a generic solution, it would be possible to concot a dynamic statement passed to execsql but it would be overkill for a one time fix.

Update all SQL NULL values in multiple columns using Column level WHERE clause?

We have a database with a bunch of wide tables (40-80 columns each) and just found a bug that introduced NULL values into about 500 of the records. The NULL values can appear in any of the columns (all are integer columns, see image below) but these NULL values are causing issues with one of our reporting systems that cannot be changed easily. We need to replace the NULL values with a specific static value (in this case 99), but since this change has to be made on a per-column basis for over 250 different columns I would rather not write individual TSQL scripts updating each column one by one.
My brain is too fried right now to think up a clever solution, so my question is how can I perform this task on all columns on a table (or better yet multiple tables) using a simple and readable SQL query. I can isolate the records easy enough using a chain of WHERE (Answer_1 IS NULL) OR (Answer_2 IS NULL) OR ... or even by AdministrationID numbers for each table, but this trick won't work when updating as where clause is per row not per column. Any advice?
Here is a sample query showing a few of the records from 4 different tables:
There isn't any convention to this -- if you want to only process records where respective columns are NULL, you need to use:
WHERE Answer_1 IS NULL
OR Answer_2 IS NULL
OR ...
But you could use this in the UPDATE statement:
UPDATE YOUR_TABLE
SET col1 = COALESCE(col1, 99),
col2 = COALESCE(col2, 99),
col3 = ...
The logic is that the value will be updated to 99 only if the column value is NULL, because of how COALESCE works--returning the first non-NULL value (processing the list provided from left to right).
Just poll the sys.columns table for each table and create some dynamic sql... It's brute force but it saves you from having to write all the t-sql out.
For example:
DECLARE #TABLENAME AS VARCHAR(255)
SET #TABLENAME = 'ReplaceWithYourTableName'
SELECT 'UPDATE ' + #TableName + ' SET ' + CAST(Name AS VARCHAR(255)) + ' = 99
WHERE ' + CAST(Name AS VARCHAR(255)) + ' IS NULL'
FROM sys.columns
WHERE object_id = OBJECT_ID(#TABLENAME)
AND system_type_id = 56 -- int's only
Since you have to do this all over the place i wrote some javascript to help you build the sql. cut and paste this into your browsers address bar to get your sql.
javascript:sql='update your table set ';x=0;while(x <= 40){sql += 'answer_'+x+ ' = coalesce(answer_'+x+',99),\n';x++;};alert(sql);
I don't like the idea to manipulate the data itself for the purpose of reporting. If you change the NULL values to 99 to just to make your reporting easier then the I consider that data as corrupted. What if there are other consumer apart from reporting which need genuine data?
I would rather write an intelligent query for the report. For example, if you use ISNULL(columnname, 99), it would return 99 whenever the column value is NULL.

T-SQL, Cursors, FETCH INTO. How to use SELECT *

I am building a one off query to iterate through a set of joined tables. The select statement is using "SELECT *". Since it's is a table with lots of fields, I don't want to specify each column as a variable. Is there a way to FETCH INTO an array or SET of some sort and just grab the values I want?
Apparently not:
INTO #variable_name[ ,...n]
"Allows data from the columns of a fetch to be placed into local variables.
Each variable in the list, from left to right, is associated with the corresponding column in the cursor result set. The data type of each variable must either match or be a supported implicit conversion of the data type of the corresponding result set column. The number of variables must match the number of columns in the cursor select list."
If you are looking to use cursors you may find better flexibility with CLR Stored procedures
Even if there was, you wouldn't want to. Fetching extra fields is one of the most common causes of performance degredation in a SQL Server application. By doing so, you restrict the optimizer's ability to use indexes effectively.
How would you propose to "grab the values that you want" without specifying column names?
Why do you need to use a cursor? Those are frowned upon in SQL Server scenarios - most of the time, they're unnecessary, and usually they're very slow and hurt performance.
What are you trying to accomplish with your cursor? Couldn't you do it in a set-based manner and use SQL Server's abilities to the max??
Marc
In 2k5 (SQL 2000 has different system objects), use the SQL metadata to quickly write queries with long lists of table/column names:
SELECT
O.Name + '__' + C.Name + ' = ' + O.Name + '.' + C.Name + ','
FROM Sys.Objects O
JOIN Sys.Columns C
ON C.Object_Id = O.Object_Id
WHERE O.Name IN ('Table1', 'Table1')
ORDER BY O.Name, C.Column_Id
I'm not sure exactly what you're trying to do with the result set, but this might be a decent start.
Also, you could declare variables as SQL_VARIANT and FETCH result sets into them like this:
DECLARE #Col1 SQL_VARIANT
SELECT #Col1 = Table1.Column1 FROM Table1
PRINT CONVERT(varchar(max), #Col1)
I'm not sure what that gains you though.
This is being suggested only for those that work with SQL daily, not specifically to answer this question.
The RedGate product SQL Prompt has the ability to expand wild-card characters into individual field names by using short-cut keys (Ctrl-B, Ctrl-W). This can save you alot of time and make it easier to remove a few fields from the query for those occasions where you do need most of them.
In SQL2005 you could also right-click the table an choose open table. Then you click the little SQL-Icon and you see the select statement, something like select * from YourTable. Clicking again on the !-icon the select * from will be expanded to the full fieldlist.
Good luck.