Sql與oracle中null值

來源:互聯網
上載者:User

1 null值的介紹
        
NULL 是資料庫中特有的資料類型,當一條記錄的某個列為 NULL ,則表示這個列的值是未知的、是不確定的。既然是未知的,就有無數種的可能性。因此, NULL 並不是一個確定的值。 這是 NULL 的由來、也是 NULL 的基礎,所有和 NULL 相關的操作的結果都可以從 NULL 的概念推匯出來。 
2 oracle中的null值介紹
    在不知道具體有什麼資料的時候,即未知,可以用NULL, 稱它為空白,ORACLE中,含有空值的表列長度為零。允許任何一種資料類型的欄位為空白,除了以下兩種情況: 
a、主鍵欄位(primary key);
b、定義時已經加了NOT NULL限制條件的欄位  
3  Oracle中null值說明: 
a、等價於沒有任何值、是未知數。 
b、NULL與0、Null 字元串、空格都不同。
c、對空值做加、減、乘、除等運算操作,結果     仍為空白。 
d、NULL的處理使用NVL函數。 
e、比較時使用關鍵字用“is null”和“is not   null”。 
f、空值不能被索引,所以查詢時有些合格資料可能查不出來, count(expr)中,用nvl(列名,0)處理後再查。 
g、排序時比其他資料都大(索引預設是降序排列,小→大), 所以NULL值總是排在最後。 
IS NULL 和IS NOT NULL 是不可分割的整體,改為IS 或IS NOT都是錯誤的,從上面我們看到了NULL 和Null 字元串的區別。

任何和NULL 的比較操作,如<>、=、<=等都返回UNKNOWN(這裡的unknown就是null,它單獨使用和布爾值false類似).判斷和比較規則總結如下:

判斷和比較規則總結表

例如:使用方法:
SQL> select 1 from dual where null=null;
沒有查到記錄
SQL> select 1 from dual where null='';
沒有查到記錄
SQL> select 1 from dual where ''='';
沒有查到記錄
SQL> select 1 from dual where null is null;
        1
---------
        1
SQL> select 1 from dual where nvl(null,0)=nvl(null,0);
        1
---------
        1

4、null做一些算術運算,比如+,-,*,/等,結果    還是null,但是對於串連操作符||,null忽略,concat函數也忽略null
SQL> select null || 'abc' from dual;

NUL
---
abc

SQL> select concat(null,'abc') from dual;

CON
---
abc

SQL> select null+10 from dual;

   NULL+10
----------


5、null相關函數規則
    
Oracle有nvl、nvl2、nullif、coalesce等函數專門處理null

 5.1 nvl(expr1,expr2)
        描述:如果expr1是null,那麼用expr2作為返回值,不是null則返回expr1.expr1與expr2一般是類型相同的,如果類型不同則會採用自動轉換,轉換失敗則報錯。
       SQL*PLUS中數值類型靠右對齊,字元靠左對齊;通過第三條語句可以看出null和‘’還是有區別的。
SQL> select nvl(null,0) from dual;

NVL(NULL,0)
-----------
          0

SQL> select nvl(to_char(null),0) from dual;

N
-
0

SQL> select nvl('',0) from dual;

N
-
0

5.2 nvl2函數

文法:nvl2(expr1,expr2,expr3)
描述:expr1如果是null,則返回expr3,否則返回expr2
expr2和expr3類型不同,expr3類型轉換為expr2類型
SQL> select nvl2(null,'1',2) from dual;

N
-
2
expr2為null,返回值類型和expr3一致
SQL> select nvl2(null,null,2) from dual;
NVL2(NULL,NULL,2)
-----------------
                2
SQL> select nvl2(null,null,'2') from dual;
N
-
2
不同類型之間的轉換,自動轉換不成功,則報錯


SQL> select nvl2(null,1,'b') from dual;
select nvl2(null,1,'b') from dual
                   *
ERROR at line 1:
ORA-01722: invalid number(無效數字)

5.3 nullif函數

文法:nullif(expr1,expr2)
描述:判斷expr1和expr2是否相等,若相等則返回null,否則返回expr1.要求expr1與expr2類型必須相同
SQL> select nullif(1,3) from dual;

NULLIF(1,3)
-----------
          1

SQL> select nullif(1,1) from dual;

NULLIF(1,1)
-----------

SQL> select nullif('1',1) from dual;
select nullif('1',1) from dual
                  *
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected CHAR got NUMBER

SQL> select nullif('ab','ab   ') from dual;

NU
--

SQL> select nullif(null,1) from dual;
select nullif(null,1) from dual
              *
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected - got CHAR

SQL> select nullif(to_char(null),'1') from dual;

N
-

5.4 coalesce函數

文法:coalesce(expr1,expr2,…,exprn)
描述:從左至右返回第一個為非null的值,若所有的列表元素都為null,則返回null。要求所有都必須為同一類型。
SQL> select coalesce(null,null,null) from dual;

C
-

SQL> select coalesce(null,1,2) from dual;

COALESCE(NULL,1,2)
------------------
                 1

SQL> select coalesce(1,'1',1) from dual;
select coalesce(1,'1',1) from dual
                  *
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected NUMBER got CHAR

6 null與索引

    Oracle中的B*Tree索引,並不儲存全為null的列,
雖然在表中建立了符合UNIQUE 索引,但是全為null的行還是可以插入的,而不是全為null的重複行則不可以插入。因為在UNIQUE約束中,(null,null)和(null,null)是不同的,當然在其他一些情況,比如說分組、集合操作中都認為全是null是相等的
SQL> create table t(a number,b number);

Table created.

SQL> create unique index idx_t on t(a,b);

Index created.

SQL> insert into t values(null,null);

1 row created.

SQL> insert into t values(1,null);

1 row created.

SQL> insert into t values(null,1);

1 row created.

SQL> commit;
SQL> insert into t values(1,null);
insert into t values(1,null)
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.IDX_T) violated

7 null的排序
  
  order by預設升序(asc),這時候null是排在最後的,如果指定降序那麼null是排在最前面的,認為null最大。
但是可以用nulls first和nulls last進行調整。
SQL> select * from emp
  2  order by comm asc;
SQL> select * from emp
  2  order by comm desc;
SQL> select *from emp
  2  order by comm asc nulls first;
SQL> select *from emp
  2  order by comm desc nulls last;

8  null與效能的關係

Not null約束,定義約束是要付出消耗效能的代價的,由下面的測試可以看出雖然約束檢查的很快,但是有時候還是很消耗資源的,至少在這個例子上是這樣的,不需要not null約束,除非必要,不要亂定義約束。
SQL> set serveroutput on
SQL> declare
  2  v_value number not null :=0;
  3  start_time number;
  4  end_time number;
  5  begin
  6  start_time :=DBMS_UTILITY.GET_TIME;
  7  FOR i in 0..100000000 LOOP
  8  v_value :=i;
  9  end LOOP;
 10  end_time :=DBMS_UTILITY.GET_TIME;
 11  DBMS_OUTPUT.PUT_LINE(end_time-start_time);
 12  END;
 13  /
1043

PL/SQL procedure successfully completed.

SQL> declare
  2  v_value number;
  3  start_time number;
  4  end_time number;
  5  begin
  6  start_time :=DBMS_UTILITY.GET_TIME;
  7  FOR i IN 0..100000000 LOOP
  8  v_value :=i;
  9  end LOOP;
 10  end_time :=DBMS_UTILITY.GET_TIME;
 11  DBMS_OUTPUT.PUT_LINE(end_time-start_time);
 12  END;
 13  /
767

9 動態語句中的綁定變數與null

在PL/SQL中動態SQL和動態PL/SQL經常使用綁定變數,這個綁定變數有個要求,就是不能直接傳入字面量null值,因為PL/SQL中動態語句要求傳入的綁定變數必須是SQL類型,而字面量null是無類型的,null字面量傳入是不可以的。當然可以採用多種方法,如果一定要傳入null,則可以將null改為空白字串、TO_NUMBER,TO_CHAR,TO_DATE等函數進行轉換,或定義一個未初始化的變數、直接傳入變數等。
SQL> create table test(id number,name varchar2(10),birth date);

Table created.

SQL> insert into test values(1,'aa',SYSDATE);

1 row created.

SQL> insert into test values(null,'aa',SYSDATE);

1 row created.

SQL> COMMIT;

Commit complete.

SQL> declare 
  2  v_sql varchar2(4000);
  3  begin
  4  v_sql :='update test set birth=:vbirth where id is null';
  5  execute immediate v_sql using null;
  6  commit;
  7  end;
  8  /
execute immediate v_sql using null;
                              *
ERROR at line 5:
ORA-06550: line 5, column 31:
PLS-00457: expressions have to be of SQL types
ORA-06550: line 5, column 1:
PL/SQL: Statement ignored
SQL> declare
  2  v_sql varchar2(4000);
  3  begin
  4  v_sql :='update test set birth=:vbirth where id is null';
  5  execute immediate v_sql using '';
  6  commit;
  7  end;
  8  /

PL/SQL procedure successfully completed.

10 sqlserver 中null值介紹
建立樣本表, Script 如下:
create table dbo. cassaba_null
(
         column1         nvarchar ( 50)            not null,
         column2         nvarchar ( 50)            null
)
go
 
insert into dbo. cassaba_null values ( '1' , null)
insert into dbo. cassaba_null values ( '2' , 'string' )
insert into dbo. cassaba_null values ( '3' , '' )
go

a.  使用 =null   / <>null       預設情況下的確不能使用 =null / <> null 來判斷 null 值如此。實際上 SQL Server 可以 使用 SET ANSI_NULLS   { ON | OFF } 設定來控制 =null / <>null 的行為。
     當 SET ANSI_NULLS 為 ON 時,即使 column_name 中包含空值,使用 WHERE column_name = NULL 的 SELECT 語句仍返回零行。
     即使 column_name 中包含非空值,使用 WHERE column_name <> NULL 的 SELECT 語句仍會返回零行
     
但是當 SET ANSI_NULLS 為 OFF 時,等於 (=) 和不等於 (<>) 比較子不遵守 ISO 標準。
      使用 WHERE column_name = NULL 的 SELECT 語句返回 column_name 中包含空值的行。
      使用 WHERE column_name <> NULL 的 SELECT 語句返回列中包含非空值的行。
      此外,使用 WHERE column_name <> XYZ_value 的 SELECT 語句返回所有不為 XYZ_value 也不為 NULL 的行。


b.   改變 null 值的串連行為  
   SQL Server 提供 SET CONCAT_NULL_YIELDS_NULL 
{ ON | OFF } 來控制 null 與其它字串串連的行為。
    當 SET CONCAT_NULL_YIELDS_NULL 為 ON 時,串聯空值與字串將產生 NULL 結果。例如, SELECT 'abc' + NULL 將產生 NULL 。
    當 SET CONCAT_NULL_YIELDS_NULL 為 OFF 時,串聯空值與字串將產生字串本身(空值作為空白字串處理)。例如, SELECT 'abc' + NULL 將產生 abc 。
    如果未指定 SET CONCAT_NULL_YIELDS ,則應用 CONCAT_NULL_YIELDS_NULL 資料庫選項的設定。
    註:在 SQL Server 的未來版本中, CONCAT_NULL_YIELDS_NULL 將始終為 ON ,而且將該選項顯式設定為 OFF 的任何應用程式都將產生一個錯誤。
c.       變數的預設值與 null 值       
      命名一個變數後,如果沒有給它賦初始值,它的值就是 null 。有時候需要注意初始 null 值和通過 select 語句給變數後期賦 null 的區別。因為此 ‘null’ 非彼 ‘null’ 。
d. 子查詢中的 null
     子查詢中出現的 null 值經常會被我們忽視,先查看下面的例子。

e. Case 語句中的 null   
Case 中的 when 語句注意不要寫成 when null,   否則得不到想要的結果。
下面的第 1 條 sql 錯誤, 2 , 3 正確。


f.  與 null 相關的函數 ISNULL ISNULL 檢測運算式是否為 NULL ,如果是的話替換 NULL 值為另外一個值 COALESCE COALESCE 函數返回指定運算式列表的第一個非 NULL 值 NULLIF 當指定的兩個運算式有相同值的時候 NULLIF 返回 NULL 值,否則返回第一個運算式的值
樣本 1 : set ansi_nulls on
declare @test1 nvarchar ( 10)
 
if ( @test1 = null)
         select 1
else
         select 2
---------------------------------------------------------------------
結果返回 2
 
樣本 2 : set ansi_nulls off
declare @test1 nvarchar ( 10)
 
if ( @test1 = null)
         select 1
else
         select 2
---------------------------------------------------------------------
結果返回 1
 
樣本 3 :
set ansi_nulls on
select * from dbo. cassaba_null where column2 != null
---------------------------------------------------------------------
無記錄返回
 
樣本 4 :
set ansi_nulls off
select * from dbo. cassaba_null where column2 != null
---------------------------------------------------------------------
返回第 2 , 3 條記錄


如果不希望每次都判斷 null, 可以使用 isnull 函數來達到每次把 null 自動替換為空白字串進行串連的效果。
樣本 5 :
declare @test nvarchar ( 50)
select isnull ( @test, '' ) + 'extend'
go
 
select   column1 + isnull ( column2, '' ) as column3 from dbo. cassaba_null
go
---------------------------------------------------------------------


樣本 6 :
declare @test nvarchar ( 50)
-- 無合格語句 , 保持預設值 null
select @test= column2 from dbo. cassaba_null where column1 = '4'
-- 有合格語句,返回的欄位值為 null ,並且賦給 @test
select @test= column2 from dbo. cassaba_null where column1 = '1'
    如果後面的代碼使用 @test 的值是否為 null 來判斷有沒有匹配的記錄,則可能發生錯誤。碰到這種狀況,我們同樣可以使用 isnull 函數來避免這個問題。
select @test= isnull ( column2, '' ) from dbo. cassaba_null where column1 = '1'
    如上面的語句,即使有匹配的記錄返回 null, 也會變成Null 字元串賦給 @test 了。這樣就把兩種情況區分開了。
樣本 7 : set ansi_nulls off
select * from cassaba_null a where a. column2 = ( select b. column2 from dbo. cassaba_null b where b. column1 = 1)
---------------------------------------------------------------------
         不管上面 ansi_nulls 設定為 on 還是 off ,始終沒有記錄返回。我們修改一下查詢語句:
select * from cassaba_null a where a. column2 in ( select b. column2 from dbo. cassaba_null b where b. column1 = 1)
         這樣,如果 ansi_nulls 設定為 on , 則沒有記錄返回。 如果設定為 off ,則會返回一條記錄。
         對於這種狀況,如果我們確定不需要返回 null 值記錄,則使用下面的 sql 語句:
select * from cassaba_null a where a. column2 in( select b. column2 from dbo. cassaba_null b where b. column1 = 1
and b. column2 is not null)
 
         反之,使用下面的語句:
select * from cassaba_null a where a. column2 in( select b. column2 from dbo. cassaba_null b where b. column1 = 1
and b. column2 is not null) or a. column2 is null


10 Sql與oracle中null值的不同
   
   a.在SQL Server中與oracle正相反,NULL值會被認為是一個無窮小的值,所以如果按照升序排列的話,則會被排在最前面
   b. SQL Server和Oracle中對插入資料值包含空的處理有所差異,在SQL Server中,我們可以把表欄位設計為非空,但我們仍然可以通過下面語句執行插入操作:
      INSERT INTO Table (TestCol) VALUES(‘’)
其中的TestCol欄位,在設計的時候,已經被設計為NOT NULL在sql server中,null和空格是不同的,也就是說,上面的語句插入的是一個空,但並不是NULL,只有當我們的插入語句中沒有該欄位的時候,才會被認為違反非空的條件約束,如果把NULL翻譯成“空”的話,可能就會很容易搞混了。此外,如果我們的欄位是INT類型的話,如果我們插入空的話,會得到一個0,也就是說,Sql server會自動幫我們處理對空格的轉化。
但是在Oracle中,這個便利便不存在了,必須嚴格按照規則來進行插入,也就是說,我們再想視圖通過插入空來滿足NOT NULL的設計約束,已經不能成功了,必須插入實實在在的內容才能符合NOT NULL的約束。
   所以相對來說oracle要比sqlserver限制要多,也就相對嚴謹

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.