It seems SQLPLUS shows nulls and empty strings for CLOBs in a way that I wasn't expecting.
Try the following in SQLPLUS (I'm using Oracle 10g Server). Create a table with a CLOB, and insert null, empty clob, and what I think of as an empty string:
create table tableA (field1 number, field2 clob);
insert into tableA values (1, null);
insert into tableA values (2, empty_clob());
insert into tableA values (3, '');
OK, lets do some queries, but first we need to tell SQLPLUS to show nulls clearly for us:
set null {NULL}
For the following query, I would have expected only row 1 returned, but it returns 2:
select * from tableA where field2 is null;
field1 field 2
-----------------------
1 {NULL}
3 {NULL}
Hmm, so '' is stored as a null in a CLOB?
Ok, so based on that result, I would now expect the following query to return all 3 rows but show {NULL} in rows 1 and 3 only. However I get this result:
select * from tableA;
field1 field 2
-----------------------
1 {NULL}
2 {NULL}
3 {NULL}
This is confusing. I thought there were only 2 nulls, even though I originally expected 1. So what's going on here? Does set null not work for CLOBs, and if so what should I use instead?
I'm actually trying to solve a different problem with null CLOB values, but this confusing behaviour has had me running rings for a while, so I'd like to understand this before I continue.
Thanks in advance
Boz
Oracle does not distinguish between NULL and an empty string. This is a well-known violation or SQL standards.
This is the reason of default string type being VARCHAR2 and not VARCHAR.
In all currently released versions they are the same, but VARCHAR is not recommended for use. This is because VARCHAR is supposed to distinguish between NULL and an empty string, while VARCHAR2, not being described in the standards, is not.
I think it's something to do with the way SQL*Plus handles empty strings and null values.
empty_clob() does not create a NULL value, but a CLOB of length zero.
Which is proven by the fact that row 2 is is not returned when you query for rows where field2 is null.
With my JDBC tool I can highlight columns that are null with a different color, and there the row with the empty_clob() is not highlighted whereas the other two are.
So I'd say it's a wrong handling of the set null option in SQL*Plus. With the following statement you will see the difference:
select field1,
nvl(field2, 'THIS IS NULL')
from tableA;
For me this displays:
field1 field 2
-----------------------
1 THIS IS NULL
2
3 THIS IS NULL
It would be interesting to see what is really in row 2. It may not truly be null as according to the documentation (see below) empty_clob() will return a initialized clob locate that does not have data (somewhat unclear on the null issue).
When executing SQL statements in SQL query tools though Oracle tends to implicitly convert CLOB's to strings which are cut off at some arbitrary length.
Purpose
EMPTY_BLOB and EMPTY_CLOB return an empty LOB locator that can be used to initialize a LOB variable or, in an INSERT or UPDATE statement, to initialize a LOB column or attribute to EMPTY. EMPTY means that the LOB is initialized, but not populated with data.
Related
Upon searching ways to replace NULL values in my table with 0 on Stack Overflow, it appears that many threads I've found point to using the COALESCE function. E.g. postgresql return 0 if returned value is null
I understand that the COALESCE function "replaces" null values for your specific query; however, the table itself remains untouched. That is, if you queried the table again in a separate query without COALESCE, null values would still exist.
My question is, is there a way for me to replace NULL values permanently in my table with a specified value (like 0) so I don't have to COALESCE in every query? And as an extension to my question, is it considered bad practice to modify the original table instead of doing manipulations in queries?
You can just do an UPDATE:
UPDATE table SET col1 = 0 WHERE col1 IS NULL;
This should effectively update all matching records on your table
I understand you got the answer but you can also use in your further query nvl function. You can replace at the runtime the NULL values with 0 just to be sure your query is working as expected.
SELECT
id
,nvl(col1, 0)
FROM
...
It's not updating in the table but you are sure that all NULL values are displayed as 0 like you want. Maybe you forget to update.
how do I query a table for a column that is clob type? I need to query the table for the column for a certain string (in addition to other conditions - I might need to use Case statement), my initial idea was to query the data in the sub-query and then find a match using Case in the top query. however I am now stuck as I am not sure how to query clob type data in Select!
Edit:
the clob column in the table is set of paragraphs, and the string I am trying to search for may be in any location in the paragraph. And I am unsure of the size of the clob.
Hope this examples illustrates clearly what i am trying to explain.
SET SQLBL ON;
SET DEFINE OFF;
CREATE TABLE CLOB_TEST
(
clob_in CLOB
);
INSERT
INTO CLOB_TEST VALUES
(
'I am working as a DBA and senior database resource in L&T Infotech in Pune India'
);
SELECT DBMS_LOB.SUBSTR(CLOB_IN,3000) ot FROM CLOB_TEST;
-----------------------------OUTPUT------------------------------------------
OT
I am working as a DBA and senior database resource in L&T Infotech in Pune India
-----------------------------OUTPUT------------------------------------------
In many respects, the same way you "query a column" (odd terminology!) of type varchar2.
table structure:
SQL> describe t
Name Null? Type
------------------------- -------- --------------------------------------------
COL1 VARCHAR2(20)
COL2 CLOB
table content:
SQL> select * from t;
COL1 COL2
-------------------- -------------------------------------------------------
abc afdreed
azx; ffare21
query the table (where clause on the CLOB column):
SQL> select * from t where col2 like '%dre%';
COL1 COL2
-------------------- -----------------------------------------------------------
abc afdreed
I would suggest you have a look on the package DBMS_LOB (link). It has some functions useful for working with LOB
for example:
Substr - The function returns amount bytes or characters of a LOB, starting from an absolute offset from the beginning of the LOB.
Insrt - This function returns the matching position of the nth occurrence of the pattern in the LOB, starting from the offset you specify.
GetLength - This function gets the length of the specified LOB. The length in bytes or characters is returned.
Trim - This procedure trims the value of the internal LOB to the length you specify in the newlen parameter. Specify the length in bytes for BLOBs, and specify the length in characters for CLOBs.
Also you can try to work with string functions. Some of them are able to work with not huge lob files.
I am playing with sqlplus command prompt, I want to display a default string, lets say 'ITISNULL' for all NULL columns without updating them.
select * from enrollments where ....
Enrollments is a table which might contain null in its lgrade column. I dont want to update it but just want an output string say, "to be graded" to be printed in its place.
Is there any SQL function I can use for this?
There are a couple ways to do this. One option is to use COALESCE:
SELECT COALSECE(lgrade, 'to be graded')...
You can't specify * for all fields, you'll have to specify each column name accordingly.
NVL is your answer, you will need to do for every column that could have nulls values
http://www.techonthenet.com/oracle/functions/nvl.php
In SQL*Plus you can use SET NULL:
SQL> SET NULL 'ITISNULL'
SQL> SELECT ...
All NULL results will display as ITISNULL. The only problem is that columns with a width of less than 8 (the length of ITISNULL) may wrap - at least they do in my older version of SQL*Plus (9.2).
To return SQL*Plus to its default, issue the following:
SQL> SET NULL ''
there are plenty of ways to show a string when the column is null. As mentioned above, some of the ways :-
Use NVL to display 'itisnull' whenever the value of col1 is null.
select nvl(col1, 'itisnull') from tableName;
Use CASE to display 'itisnull' whenever the value of col1 is null.
select
case when col1 is null then
'itisnull'
else col1
end colum from tableName;
I'm running a pretty standard
INSERT INTO [table] (col1, col2, ...coln)
select * from #temp
and I'm getting the following error:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the varchar value 'NULL' to data type int.
I understand the error, but want to know why the column that is causing issue isn't identified by the error message. Is there an easy way to find which column contains the naughty null or is this just a ploy to make me look like I'm being productive at work while I really just spent 30 minutes looking at a huge result set without getting anywhere?
Edit: Thanks for the help guys, but no one really answered the question. Do all RDBMS's spew out similar error messages are or some more helpful? Its 2012...trial and error over possibly thousands of columns should be dead!
I would look at how you populate the temp table. You appear to be getting a value of 'null' not NULL. If this data is coming from a Excel file, this is a common problem. I usually clease the data first by updating this way:
Update #temp
set field1 = NULL
where field1 = 'NULL'
If you want to do all in the same update command, then
Update #temp
set field1 = NULLIF(field1, 'NULL')
, field2 = NULLIF(field2, 'NULL')
, field3 = NULLIF(field3, 'NULL')
It shouldn't take you 30 minutes to figure out where the null is. You only have so many columns. Just start selecting from #temp WHERE col1 IS NULL, then WHERE col2 is.
If #temp has a VARCHAR column you're trying to put into in INT column then cast it. If there are NULLs you might want to handle them with an CAST(ISNULL(VarCharColumn, '0') AS INT) or something. If an INT column allows NULLS, then just the cast to INT should be enough (as long as all the values are NULL or a valid int).
If you write your INSERT with a little bit more care then you should be able to get the results you want.
You're going to need some trial and error as #Jeremy pointed out. But you can winnow down the choices.
The error message says that the problem is a NULL in a varchar column. You can restrict your searching to just the varchar columns in #temp: select * from #temp where col1 is null or col3 is null
Second, the problem is also happening when the database engine tries to convert a null varchar value to an integer not null. Compare the definitions of both tables to see where a varchar in #temp matches up with an integer not null in the other table.
This, however, is suspicious. Why are you trying to convert text to numbers? If that's what you really want to do, you will probably need an explicit cast from textual to numeric.
If you run these two statements before your query you will see null values on those columns in the results set:
SET ARITHABORT OFF
SET ANSI_WARNINGS OFF
imagine there are 50 columns. I dont wan't any row that includes a null value. Are there any tricky way?
SQL 2005 server
Sorry, not really. All 50 columns have to be checked in one form or another.
Column1 IS NOT NULL AND ... AND Column50 IS NOT NULL
Of course, under these conditions why not disallow NULLs in the first place by having NOT NULL in the table definition
If it's SQL Server 2005+ you can do something like:
SELECT fields
FROM MyTable
WHERE stuff
EXCEPT -- This excludes the below results
SELECT fields
FROM MyTable
WHERE (Col1 + Col2 + Col3....) IS NULL
Adding a null to a value results in a null, so the sum of all your columns will be NULL.
This may need to change based on your data types, but adding NULL to either a char/varchar or a number will result in another NULL.
If you are looking at the values not being null, you can do this in the select statement.
SELECT ISNULL(firstname,''), ISNULL(lastname,'') FROM TABLE WHERE SOMETHING=1
This will replace nulls with string blanks. If you want another value use: ISNULL(firstname,'empty') for example. You can use anything where the word empty is.
I prefer this query
select *
from table
where column1>''
and column2>''
and (column3>'' or column3<'')
Allows sql server to use an index seek if the proper index/es exist. you would have to do the syntext for column 3 for any numeric values that could be negative.