kxbin
          成功留給有準(zhǔn)備的人
          posts - 10,  comments - 35,  trackbacks - 0

          NULL是數(shù)據(jù)庫(kù)中特有的數(shù)據(jù)類型,當(dāng)一條記錄的某個(gè)列為NULL,則表示這個(gè)列的值是未知的、是不確定的。既然是未知的,就有無(wú)數(shù)種的可能性。因此,NULL并不是一個(gè)確定的值。

          這是NULL的由來(lái)、也是NULL的基礎(chǔ),所有和NULL相關(guān)的操作的結(jié)果都可以從NULL的概念推導(dǎo)出來(lái)。

          判斷一個(gè)字段是否為NULL,應(yīng)該用IS NULL或IS NOT NULL,而不能用‘=’。對(duì)NULL的判斷只能定性,既是不是NULL(IS NULL/IS NOT NULL),而不能定值。簡(jiǎn)單的說(shuō),由于NULL存在著無(wú)數(shù)的可能,因此兩個(gè)NULL不是相等的關(guān)系,同樣也不能說(shuō)兩個(gè)NULL就不相等,或者比較兩個(gè)NULL的大小,這些操作都是沒(méi)有意義,得不到一個(gè)確切的答案的。因此,對(duì)NULL的=、!=、>、<、>=、<=等操作的結(jié)果都是未知的,也就算說(shuō),這些操作的結(jié)果仍然是NULL。

          同理,對(duì)NULL進(jìn)行+、-、*、/等操作的結(jié)果也是未知的,所以也是NULL。

          所以,很多時(shí)候會(huì)這樣總結(jié)NULL,除了IS NULL、IS NOT NULL以外,對(duì)NULL的任何操作的結(jié)果還是NULL。

          上面這句話總結(jié)的很精辟,而且很好記,所以很多時(shí)候人們只記得這句話,而忘了這句話是如何得到的。其實(shí)只要清楚NULL的真正含義,在處理NULL的時(shí)候就不會(huì)出錯(cuò)。

          說(shuō)了怎么多,來(lái)看一個(gè)經(jīng)典的例子:

          SQL> CREATE OR REPLACE PROCEDURE P1 (P_IN IN NUMBER) AS
          2 BEGIN
          3 IF P_IN >= 0 THEN 
          4 DBMS_OUTPUT.PUT_LINE('TRUE');
          5 ELSE
          6 DBMS_OUTPUT.PUT_LINE('FALSE');
          7 END IF;
          8 END;
          9 /

          過(guò)程已創(chuàng)建。

          SQL> CREATE OR REPLACE PROCEDURE P2 (P_IN IN NUMBER) AS
          2 BEGIN
          3 IF P_IN < 0 THEN 
          4 DBMS_OUTPUT.PUT_LINE('FALSE');
          5 ELSE
          6 DBMS_OUTPUT.PUT_LINE('TRUE');
          7 END IF;
          8 END;
          9 /

          過(guò)程已創(chuàng)建。

          上面兩個(gè)過(guò)程是否是等價(jià)的?對(duì)于熟悉C或JAVA的開(kāi)發(fā)人員來(lái)說(shuō),可能認(rèn)為二者是等價(jià)的,但是在數(shù)據(jù)庫(kù)中,則還要考慮到NULL的情況。

          當(dāng)輸入為NULL時(shí),可以看到上面兩個(gè)過(guò)程不同的輸出:

          SQL> SET SERVEROUT ON
          SQL> EXEC P1(NULL)
          FALSE

          PL/SQL 過(guò)程已成功完成。

          SQL> EXEC P2(NULL)
          TRUE

          PL/SQL 過(guò)程已成功完成。

          輸入為NULL時(shí),上面兩個(gè)過(guò)程中的判斷的結(jié)果都是一樣的,不管是NULL >= 0還是NULL < 0結(jié)果都是未知,所以兩個(gè)判斷的結(jié)果都是NULL。最終,在屏幕上輸出的都是ELSE后面跟的輸出值。

          由于NULL所具有的特殊性,在處理數(shù)據(jù)庫(kù)相關(guān)問(wèn)題時(shí)應(yīng)該對(duì)NULL的情況額外考慮,否則很容易造成錯(cuò)誤。
           

          由于引入了NULL,在處理邏輯過(guò)程中一定要考慮NULL的情況。同樣的,數(shù)據(jù)庫(kù)中的布爾值的處理,也是需要考慮NULL的情況,這使得布爾值從原來(lái)的TRUE、FALSE兩個(gè)值變成了TRUE、FALSE和NULL三個(gè)值。

          下面是TRUE和FALSE兩種情況進(jìn)行布爾運(yùn)算的結(jié)果:

          AND操作:

          AND

          TRUE

          FALSE

          TRUE

          TRUE

          FALSE

          FALSE

          FALSE

          FALSE

          OR操作:

          OR

          TRUE

          FALSE

          TRUE

          TRUE

          TRUE

          FALSE

          TRUE

          FALSE

          上面是熟悉的TRUE和FALSE兩個(gè)值進(jìn)行布爾運(yùn)算的結(jié)果,如果加上一個(gè)NULL的情況會(huì)怎樣?NULL的布爾運(yùn)算是否會(huì)像NULL的算術(shù)運(yùn)算那樣結(jié)果都是NULL呢?下面通過(guò)一個(gè)過(guò)程來(lái)進(jìn)行說(shuō)明:

          SQL> SET SERVEROUT ON SIZE 100000
          SQL> DECLARE
          2 TYPE T_BOOLEAN IS TABLE OF BOOLEAN INDEX BY BINARY_INTEGER;
          3 V_BOOL1 T_BOOLEAN;
          4 V_BOOL2 T_BOOLEAN;

          6 PROCEDURE P(P_IN1 BOOLEAN, P_IN2 BOOLEAN, P_OPERATOR IN VARCHAR2) AS
          7 V_RESULT BOOLEAN;
          8 BEGIN
          9 IF P_IN1 IS NULL THEN
          10 DBMS_OUTPUT.PUT('NULL ');
          11 ELSIF P_IN1 THEN
          12 DBMS_OUTPUT.PUT('TRUE ');
          13 ELSE
          14 DBMS_OUTPUT.PUT('FALSE ');
          15 END IF;
          16 
          17 IF P_OPERATOR = 'AND' THEN
          18 DBMS_OUTPUT.PUT('AND ');
          19 V_RESULT := P_IN1 AND P_IN2;
          20 ELSIF P_OPERATOR = 'OR' THEN
          21 DBMS_OUTPUT.PUT('OR ');
          22 V_RESULT := P_IN1 OR P_IN2;
          23 ELSE
          24 RAISE_APPLICATION_ERROR('-20000', 'INPUT PARAMETER P_OPERATOR ERROR');
          25 END IF;
          26 
          27 IF P_IN2 IS NULL THEN
          28 DBMS_OUTPUT.PUT('NULL');
          29 ELSIF P_IN2 THEN
          30 DBMS_OUTPUT.PUT('TRUE');
          31 ELSE
          32 DBMS_OUTPUT.PUT('FALSE');
          33 END IF;
          34 
          35 IF V_RESULT IS NULL THEN
          36 DBMS_OUTPUT.PUT(':NULL');
          37 ELSIF V_RESULT THEN
          38 DBMS_OUTPUT.PUT(':TRUE');
          39 ELSE
          40 DBMS_OUTPUT.PUT(':FALSE');
          41 END IF;
          42 DBMS_OUTPUT.NEW_LINE;
          43 END;
          44 
          45 BEGIN
          46 V_BOOL1(1) := TRUE;
          47 V_BOOL1(2) := FALSE;
          48 V_BOOL1(3) := NULL;
          49 V_BOOL2 := V_BOOL1;
          50 FOR I IN 1..V_BOOL1.COUNT LOOP
          51 FOR J IN 1..V_BOOL2.COUNT LOOP
          52 P(V_BOOL1(I), V_BOOL2(J), 'AND');
          53 P(V_BOOL1(I), V_BOOL2(J), 'OR');
          54 END LOOP;
          55 END LOOP; 
          56 END;
          57 /
          TRUE AND TRUE:TRUE
          TRUE OR TRUE:TRUE
          TRUE AND FALSE:FALSE
          TRUE OR FALSE:TRUE
          TRUE AND NULL:NULL
          TRUE OR NULL:TRUE
          FALSE AND TRUE:FALSE
          FALSE OR TRUE:TRUE
          FALSE AND FALSE:FALSE
          FALSE OR FALSE:FALSE
          FALSE AND NULL:FALSE
          FALSE OR NULL:NULL
          NULL AND TRUE:NULL
          NULL OR TRUE:TRUE
          NULL AND FALSE:FALSE
          NULL OR FALSE:NULL
          NULL AND NULL:NULL
          NULL OR NULL:NULL

          PL/SQL 過(guò)程已成功完成。

          由于NULL是未知,所以NULL AND NULL、NULL OR NULL、NULL AND TRUE和NULL OR FALSE的值都是未知的,這些的結(jié)果仍然是NULL。

          那么為什么NULL AND FALSE和NULL OR TRUE得到了一個(gè)確定的結(jié)果呢?仍然從NULL的概念來(lái)考慮。NULL是未知的,但是目前NULL的類型是布爾類型,因此NULL只有可能是TRUE或者FALSE中的一個(gè)。

          而根據(jù)前面的表格,TRUE AND FALSE和FALSE AND FALSE的結(jié)果都是FALSE,也就是說(shuō)不管NULL的值是TRUE還是FALSE,它與FALSE進(jìn)行AND的結(jié)果一定是FALSE。

          同樣的道理,TRUE AND TRUE和FALSE AND TRUE的結(jié)果都是TRUE,所以不管NULL取何值,NULL和TRUE的OR的結(jié)果都是TRUE。

          AND操作圖表變?yōu)椋?/span>

          AND

          TRUE

          FALSE

          NULL

          TRUE

          TRUE

          FALSE

          NULL

          FALSE

          FALSE

          FALSE

          FALSE

          NULL

          NULL

          FALSE

          NULL

          OR操作圖表變?yōu)椋?/span>

          OR

          TRUE

          FALSE

          NULL

          TRUE

          TRUE

          TRUE

          TRUE

          FALSE

          TRUE

          FALSE

          NULL

          NULL

          TRUE

          NULL

          NULL

          最后,仍然來(lái)看一個(gè)例子:

          SQL> SELECT * FROM TAB;

          TNAME TABTYPE CLUSTERID
          ------------------------------ ------- ----------
          PLAN_TABLE TABLE
          T TABLE
          T1 TABLE
          T2 TABLE
          T3 TABLE
          TEST TABLE
          TEST1 TABLE
          TEST_CORRUPT TABLE
          T_TIME TABLE

          已選擇9行。

          SQL> SELECT * FROM TAB WHERE TNAME IN ('T', 'T1', NULL);

          TNAME TABTYPE CLUSTERID
          ------------------------------ ------- ----------
          T TABLE
          T1 TABLE

          SQL> SELECT * FROM TAB WHERE TNAME NOT IN ('T', 'T1', NULL);

          未選定行

          對(duì)于IN和NOT IN與NULL的關(guān)系前面并沒(méi)有說(shuō)明,不過(guò)可以對(duì)其進(jìn)行簡(jiǎn)單的變形:

          TNAME IN (‘T’, ‘T1’, NULL) < = > TNAME = ‘T’ OR TNAME = ‘T1’ OR TNAME = NULL

          根據(jù)前面的結(jié)果,當(dāng)查詢到T或T1這兩條記錄時(shí),WHERE條件相當(dāng)于TRUE AND FALSE AND NULL,其結(jié)果是TRUE,因此返回了兩條記錄。

          TNAME NOT IN (‘T’, ‘T1’, NULL) < = > TNAME != ‘T’ AND TNAME != ‘T1’ AND TNAME != NULL。

          WHERE條件相當(dāng)于TRUE AND TRUE AND NULL,或TRUE AND FA發(fā)現(xiàn)很多人對(duì)空字符串’’不是很清楚,這里簡(jiǎn)單總結(jié)一下。

          以前我總說(shuō)空字符串’’等價(jià)于NULL,但是有些人喜歡鉆牛角尖,所以我改一下說(shuō)法,空字符串’’是NULL的字符類型的表現(xiàn)格式。

          也許有人會(huì)認(rèn)為,NULL就是NULL,本身沒(méi)有類型的一說(shuō),但是我認(rèn)為,NULL還是有類型的,只不過(guò)不同類型的NULL都用相同的關(guān)鍵字NULL來(lái)表示。而且,NULL本身也可以轉(zhuǎn)化為任意類型的數(shù)據(jù),因此給人的感覺(jué)是NULL沒(méi)有數(shù)據(jù)類型。

          其實(shí)NULL不但有數(shù)據(jù)類型,還有默認(rèn)的數(shù)據(jù)類型,那就是字符類型。至于這個(gè)答案是如何推斷出來(lái)的,請(qǐng)看:http://yangtingkun.itpub.net/post/468/50132

          不過(guò)上面說(shuō)的這個(gè)默認(rèn)的數(shù)據(jù)類型是在極限的情況下測(cè)試出來(lái)的,如果只是給出一個(gè)NULL,那么它是可以代表任意的類型的。

          證明空字符串就是NULL是很容易的:

          SQL> SELECT 1 FROM DUAL WHERE '' = '';

          未選定行

          SQL> SELECT 1 FROM DUAL WHERE '' IS NULL;

          1
          ----------
          1

          SQL> SELECT DUMP(''), DUMP(NULL) FROM DUAL;

          DUMP DUMP
          ---- ----
          NULL NULL

          上面三個(gè)SQL語(yǔ)句,任意一個(gè)都足以證明空字符串’’就是NULL。

          有些人可能會(huì)說(shuō),既然’’就是NULL,為什么不能進(jìn)行IS ’’的判斷呢?

          SQL> SELECT 1 FROM DUAL WHERE '' IS '';
          SELECT 1 FROM DUAL WHERE '' IS ''
          *
          第 1 行出現(xiàn)錯(cuò)誤:
          ORA-00908: 缺失 NULL 關(guān)鍵字

          其實(shí)從上面的錯(cuò)誤信息就可以看到答案。原因就是IS NULL是Oracle的語(yǔ)法,在Oracle運(yùn)行的時(shí)刻’’是NULL,但是現(xiàn)在Oracle還沒(méi)有運(yùn)行這句SQL,就由于語(yǔ)法不正確被SQL分析器擋住了。Oracle的語(yǔ)法并不包含IS ’’的寫法,所以,這一點(diǎn)并不能稱為’’不是NULL的理由。

          那么我為什么還要說(shuō)’’是NULL的字符表示形式呢?因?yàn)?#8217;’和NULL還確實(shí)不完全一樣,對(duì)于NULL來(lái)說(shuō),它表示了各種數(shù)據(jù)類型的NULL值。而對(duì)于空字符串’’來(lái)說(shuō),雖然它也具有NULL的可以任意轉(zhuǎn)化為其他任何數(shù)據(jù)類型的特點(diǎn),但是無(wú)論是從形式上還是從本質(zhì)上它都表現(xiàn)出了字符類型的特點(diǎn)。

          下面通過(guò)一個(gè)例子來(lái)證明’’本質(zhì)是字符類型的NULL。

          SQL> CREATE OR REPLACE PACKAGE P_TEST_NULL AS
          2 FUNCTION F_RETURN (P_IN IN NUMBER) RETURN VARCHAR2;
          3 FUNCTION F_RETURN (P_IN IN VARCHAR2) RETURN VARCHAR2;
          4 END;
          5 /

          程序包已創(chuàng)建。

          SQL> CREATE OR REPLACE PACKAGE BODY P_TEST_NULL AS 

          3 FUNCTION F_RETURN (P_IN IN NUMBER) RETURN VARCHAR2 AS
          4 BEGIN
          5 RETURN 'NUMBER';
          6 END;

          8 FUNCTION F_RETURN (P_IN IN VARCHAR2) RETURN VARCHAR2 AS
          9 BEGIN
          10 RETURN 'VARCHAR2';
          11 END;
          12 
          13 END;
          14 /

          程序包體已創(chuàng)建。

          SQL> SELECT P_TEST_NULL.F_RETURN(3) FROM DUAL;

          P_TEST_NULL.F_RETURN(3)
          ------------------------------------------------------------
          NUMBER

          SQL> SELECT P_TEST_NULL.F_RETURN('3') FROM DUAL;

          P_TEST_NULL.F_RETURN('3')
          ------------------------------------------------------------
          VARCHAR2

          SQL> SELECT P_TEST_NULL.F_RETURN('') FROM DUAL;

          P_TEST_NULL.F_RETURN('')
          ------------------------------------------------------------
          VARCHAR2

          SQL> SELECT P_TEST_NULL.F_RETURN(NULL) FROM DUAL;
          SELECT P_TEST_NULL.F_RETURN(NULL) FROM DUAL
          *
          第 1 行出現(xiàn)錯(cuò)誤:
          ORA-06553: PLS-307: 有太多的 'F_RETURN' 聲明與此次調(diào)用相匹配

          從這一點(diǎn)上可以看出’’實(shí)際上已經(jīng)具備了數(shù)據(jù)類型。所以我將’’表述為空字符串是NULL的字符類型表現(xiàn)形式。LSE AND NULL,其最終結(jié)果是NULL或者FALSE,所以,查詢不會(huì)返回記錄。
           
           

          posted on 2012-08-30 16:13 kxbin 閱讀(326) 評(píng)論(0)  編輯  收藏 所屬分類: ORACLE 、轉(zhuǎn)發(fā)
          你恨一個(gè)人是因?yàn)槟銗?ài)他;你喜歡一個(gè)人,是因?yàn)樗砩嫌心銢](méi)有的;你討厭一個(gè)人是因?yàn)樗砩嫌心阌械臇|西;你經(jīng)常在別人面前批評(píng)某人,其實(shí)潛意識(shí)中是想接近他。

          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          常用鏈接

          留言簿(5)

          隨筆檔案

          文章分類

          文章檔案

          相冊(cè)

          收藏夾

          J2EE

          java技術(shù)網(wǎng)站

          Linux

          平時(shí)常去的網(wǎng)站

          數(shù)據(jù)庫(kù)

          電影網(wǎng)站

          網(wǎng)站設(shè)計(jì)

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 南乐县| 溧水县| 泊头市| 上林县| 威海市| 青神县| 泾川县| 铜川市| 日土县| 旌德县| 崇州市| 祁门县| 察雅县| 武乡县| 马鞍山市| 柳林县| 崇州市| 名山县| 泰来县| 安阳县| 灵山县| 贵定县| 镇雄县| 盐边县| 永嘉县| 宜都市| 盐源县| 万源市| 蚌埠市| 巴彦淖尔市| 于都县| 石嘴山市| 衡南县| 靖宇县| 洛川县| 宁国市| 石屏县| 五寨县| 杭州市| 荔浦县| 高阳县|