NULLノヌト

みなさんこんにちは
長い間Oracleに぀いお圹に立぀ず考えおいたので、私はたくさんのトピックを詊したした。 それが長すぎるこずが刀明したたびに、それは野生に深く吹き蟌んだので。 したがっお、私は聎衆の興味ずその資料のプレれンテヌションのスタむルずの関係を評䟡するために、可胜な限り単玔なトピックから始めるこずにしたしたIMHO、筆者は私からあたり良くありたせん。 いく぀かのメモだから。

キヌポむント

特別な倀NULLは、デヌタが存圚しないこずを意味したす。これは、倀が䞍明であるずいう事実の衚明です。 デフォルトでは、 NOT NULL制玄が課されおいない限り、任意のタむプの列ず倉数がこの倀を受け入れるこずができたす。 たた、DBMSは、テヌブルのプラむマリキヌに含たれる列にNOT NULLを自動的に远加したす。

NULLの䞻な機胜は、䜕にも等しくないこず、さらに別のNULLでさえないこずです。 挔算子を䜿甚しお倀を比范するこずはできたせん = 、 < 、 > 、 like ...匏NULL != NULLさえも、未知のものを明確に比范できないため、真ではありたせん。 ちなみに、条件を蚈算するずき、Oracleはず制限されないため、この匏もfalseになりたせん。 NULLの圢匏で䞍確実性の芁玠が存圚するため、別の状態たす。

したがっお、Oracleは2倀ではなく3倀のロゞックで動䜜したす。 祖父コッドは圌のリレヌショナル理論にこの特城を眮いおおり、リレヌショナルDBMSであるOracleは圌の教蚓に完党に埓っおいたす。 「奇劙な」ク゚リ結果を黙想しないために、開発者は3倀論理の真理倀衚を知る必芁がありたす。 たずえば、英語版のWikipedia Three-valued_logicで芋るこずができたす。

䟿宜䞊、ブヌルパラメヌタの状態を出力するプロシヌゞャを䜜成したす。
 create procedure test_bool( p_bool boolean ) is begin case when p_bool = true then dbms_output.put_line('TRUE'); when p_bool = false then dbms_output.put_line('FALSE'); else dbms_output.put_line('UNKNOWN'); end case; end test_bool; 

メッセヌゞをコン゜ヌルに出力するオプションを有効にしたす。
 set serveroutput on 

䜿い慣れた比范挔算子は、NULLの前に枡されたす。
 exec test_bool( null = null ); -- UNKNOWN exec test_bool( null != null ); -- UNKNOWN exec test_bool( null = 'a' ); -- UNKNOWN exec test_bool( null != 'a' ); -- UNKNOWN 


NULLずの比范


IS NULLずの比范を可胜にする特別なIS NULLおよびIS NOT NULL挔算子がIS NOT NULL 。 IS NULLは、オペランドがNULL堎合はtrueを返し、そうでない堎合はfalseをNULL 。

 select case when null is null then 'YES' else 'NO' end from dual; -- YES select case when 'a' is null then 'YES' else 'NO' end from dual; -- NO 

したがっお、 IS NOT NULLは逆の動䜜をしIS NOT NULLオペランド倀がNULL以倖の堎合はtrueを返し、NULLの堎合はfalseを返したす。

 select case when 'a' is NOT null then 'YES' else 'NO' end from dual; -- YES select case when null is NOT null then 'YES' else 'NO' end from dual; -- NO 

さらに、欠損倀ずの比范に関する芏則にはいく぀かの䟋倖がありたす。 1぀はDECODE関数で、2぀のNULLを互いに同等ず芋なしたす。 次に、これらは耇合むンデックスです。2぀のキヌに空のフィヌルドが含たれおいおも、空でないフィヌルドがすべお等しい堎合、Oracleはこれら2぀のキヌを同等ず芋なしたす。

DECODEはシステムに反したす
 select decode( null , 1, 'ONE' , null, 'EMPTY' --     , 'DEFAULT' ) from dual; 

耇合むンデックスの䟋は、むンデックスセクションにありたす。

論理挔算ずNULL

通垞、 状態はず同じ方法で凊理され 。 たずえば、テヌブルから行を遞択し、 WHEREで条件x = NULLを評䟡するされる堎合、単䞀の行は取埗されたせん。 ただし、違いがあり()匏()がtrueを返す堎合、 ()は返したす。 䞍明な状態を凊理する堎合、論理挔算子ANDおよびORも独自の特性がありたす。 以䞋の䟋の詳现。

ほずんどの堎合、未知の結果はずしお扱われ 。
 select 1 from dual where dummy = null; --     

未知の吊定は未知を䞎えたす
 exec test_bool( not(null = null) ); -- UNKNOWN exec test_bool( not(null != null) ); -- UNKNOWN exec test_bool( not(null = 'a') ); -- UNKNOWN exec test_bool( not(null != 'a') ); -- UNKNOWN 

OR挔算子
 exec test_bool( null or true ); -- TRUE <- !!!!! exec test_bool( null or false ); -- UNKNOWN exec test_bool( null or null ); -- UNKNOWN 

AND挔算子
 exec test_bool( null and true ); -- UNKNOWN exec test_bool( null and false ); -- FALSE <- !!!!! exec test_bool( null and null ); -- UNKNOWN 


挔算子INおよびNOT IN


たず、いく぀かの準備手順を行いたす。 テストのために、1぀の数倀列Aず4぀の行を持぀テヌブルTを䜜成したす 1, 2, 3およびNULL
 create table t as select column_value a from table(sys.odcinumberlist(1,2,3,null)); 

リク゚ストトレヌスをPLUSTRACE このためには、 PLUSTRACEロヌルが必芁です。
トレヌスからのリストでは、芁求で指定された条件が展開されおいるこずを瀺すために、フィルタヌ郚分のみが残されおいたす。
 set autotrace on 

準備手順は完了したした。次に、オペレヌタヌず協力したしょう。 セット(1, 2, NULL)すべおのレコヌドを遞択しおみたしょう。
 select * from t where a in(1,2,null); --  [1,2] -- Predicate Information: -- filter("A"=1 OR "A"=2 OR "A"=TO_NUMBER(NULL)) 

ご芧のずおり、NULLの行は遞択されおいたせん。 これは、述語"A"=TO_NUMBER(NULL)の蚈算で状態返されたために発生したした。 ク゚リ結果にNULLを含めるには、これを明瀺的に指定する必芁がありたす。

 select * from t where a in(1,2) or a is null; --  [1,2,NULL] -- Predicate Information: -- filter("A" IS NULL OR "A"=1 OR "A"=2) 

NOT IN詊しおみたしょう
 select * from t where a not in(1,2,null); -- no rows selected -- Predicate Information: -- filter("A"<>1 AND "A"<>2 AND "A"<>TO_NUMBER(NULL)) 


通垞、単䞀の゚ントリではありたせん トリプルがク゚リ結果に入らなかった理由を芋おみたしょう。 DBMSがケヌスA=3䜿甚したフィルタヌを手動で蚈算したす。

  3 <> 1 AND 3 <> 2 AND 3 <> to_numberNULL
    \ / \ / \ /
   真ず真ず未知
        \ / /
        真および未知
             \ /
             䞍明 

3倀ロゞックの特性により、 NOT INはNULLずたったく友奜的ではありNOT IN 。NULLが遞択条件に入るずすぐに、デヌタを埅機しないでください。

NULLおよび空の文字列


ここで、OracleはANSI SQL暙準から離れ、NULLず空の文字列の等䟡性を宣蚀したす。 これはおそらく最も議論の䜙地のある機胜の1぀であり、個人ぞの移行を䌎う耇数ペヌゞの議論を匕き起こし、お互いに糞䟿を泚ぎ、厳しい玛争のその他の䞍可欠な属性をもたらしたす。 ドキュメントから刀断するず、Oracle自䜓はこの状況を倉曎するこずを気にかけたせん空の文字列は珟圚NULLずしお扱われおいたすが、これは将来のリリヌスで倉曎される可胜性があるず蚀いたすが、今日、このDBMS甚に曞かれた非垞に倧量のコヌドがありたすシステムの動䜜を倉曎するこずはほずんど珟実的ではありたせん。 さらに、圌らは少なくずもDBMSの7番目のバヌゞョン1992-1996でこのこずに぀いお話し始め、珟圚では12番目のバヌゞョンが準備䞭です。

NULLず空の文字列は同等です。
 exec test_bool( '' is null ); -- TRUE 


激しい玛争の䞍可欠な属性
 select count(*) comments_count, avg(c.vote) avg_vote from habr.comments c join habr.posts p on( c.post_id = p.id ) where lower(p.title) like '%%' and lower(p.title) like '%%'; COMMENTS_COUNT AVG_VOTE --------------- --------- 100500 -100 

クラシックの原則に埓っおルヌトを芋るず、空の文字列ずNULLが同等である理由は、デヌタブロック内のvarcharsずNULLのストレヌゞ圢匏にありたす。 Oracleは、ヘッダヌずそれに続くデヌタの列で構成される構造にテヌブル行を栌玍したす。 各列は、列のデヌタ長1たたは3バむトず実際にはデヌタ自䜓の2぀のフィヌルドで衚されたす。 varchar2長さがれロの堎合、デヌタフィヌルドに曞き蟌むものはなく、バむトを占有せず、特別な倀0xFFが長さずずもにフィヌルドに曞き蟌たれ、デヌタがないこずを瀺したす。 NULLはたったく同じ方法で衚瀺されたす。デヌタフィヌルドはなく、長さのあるフィヌルドに0xFFが曞き蟌たれたす。 もちろん、Oracle開発者はこれらの2぀の状態を分離できたすが、初期の頃からは、これらの状態が慣習でした。

個人的には、空の文字列ずNULLの等䟡性は非垞に自然で論理的なもののようです。 「空の文字列」ずいう名前自䜓は、意味の欠劂、空、ドヌナツの穎を意味したす。 䞀般に、NULLは同じこずを意味したす。 しかし、䞍快な結果がありたす。空の文字列がれロであるず自信を持っお蚀える堎合、NULLの長さは定矩されたせん。 したがっお、圓然のこずながら、匏のlength('')はれロではなくNULLを返したす。 別の問題空の文字列ず比范するこずはできたせん。 匏val = ''は、本質的にはval = NULLず同等であるため、状態を返しval = NULL 。

空の文字列の長さは定矩されおいたせん。
 select length('') from dual; -- NULL 

空の文字列ずの比范はできたせん。
 exec test_bool( 'a' != '' ); -- UNKNOWN 

オラクルが提案したアプロヌチの批評家は、空の行が必ずしもあいたいさを意味するずは蚀いたせん。 たずえば、営業郚長は顧客カヌドに蚘入したす。 圌は自分の連絡先電話番号555-123456を瀺すこずができ、圌が䞍明NULLであるこずを瀺すこずができ、たた連絡先電話番号がないこず空の行を瀺すこずもできたす。 空の行を栌玍するオラクルの方法では、最埌のオプションを実装するのに問題がありたす。 セマンティクスの芳点からは、匕数は正しいのですが、完党な答えを受け取ったこずがない質問が垞にありたす。「電話」フィヌルドに空の行を入力する方法ず、NULLずさらに区別する方法を教えおください。 もちろん、オプションがありたすが、それでも...

実際、PL / SQLに関しおは、゚ンゞンの内郚のどこかで、空の文字列ずNULLは異なりたす。 これを確認する1぀の方法は、連想コレクションを䜿甚するず、むンデックス'' 空の文字列を持぀芁玠を保存できるが、むンデックスNULLを持぀芁玠を保存できないずいう事実によるものです。

 declare procedure empty_or_null( p_val varchar2 ) is type tt is table of varchar2(1) index by varchar2(10); t tt; begin if p_val is not null then dbms_output.put_line(' '); else --      p_val t(p_val) := 'x'; -- ! ,   dbms_output.put_line(' '); end if; exception --     p_val  . , NULL when others then dbms_output.put_line('NULL'); end; begin empty_or_null( 'qwe' ); --   empty_or_null( '' ); --   empty_or_null( NULL ); -- NULL end; 

このようなフェむントを実際に耳で䜿甚するこずは䟡倀がありたせん。 問題を回避するには、ドックからルヌルを孊習するこずをお勧めしたす。空の文字列ず区別できないもののNULLです。

数孊ヌル

この小さなパラグラフは、金曜日のREN-TV映画を背景に、金曜日の倜にビヌルのために曞かれたした。 圌の怠inessを曞き盎しお、すみたせん。

チャレンゞ。 マヌシャは、コリャず結婚する前に未知の数の恋人がいたした。 コリャは、結婚埌、マヌシャがサヌシャずノィティダずセックスをしたこずを知っおいたす。 Kolyaの恋人マヌシャの正確な数を芋぀けるのに圹立ちたす。

明らかに、Kolyaを支揎するこずはできたせん。Mashaの恋人の数が䞍明であるため、結婚によっおすべおの蚈算が1぀の倀に枛少したす-䞍明です。 オラクルは、オラクルず呌ばれおいたしたが、この質問では霊魂の戊いの参加者よりも先に進むこずはありたせん。明癜な質問に察しおのみ明癜な答えを䞎えたす。 しかし、オラクルはもっず正盎であるこずを認めなければなりたせん。コリダの堎合、圌は粟神分析に埓事せず、すぐに「わからない」ず蚀うでしょう。
 select decode( null + 10, null, '', '') a from dual; --  select decode( null * 10, null, '', '') a from dual; --  select decode( abs(null), null, '', '') a from dual; --  select decode( sign(null), null, '', '') a from dual; --  

連結は異なりたす。文字列にNULLを远加できたすが、これは倉曎したせん。 これが二重基準の方針です。
 select null ||'AA'|| null ||'BB'|| null from dual; -- AABB 


NULLおよび集玄関数


COUNT陀くほずんどすべおの集蚈関数垞にそうであるずは限りたせんは、蚈算の空の倀を無芖したす。 圌らがこれを行わなかった堎合、最初にNULLが点滅するず、関数の結果が䞍明な倀になりたす。 たずえば、 SUM関数を䜿甚したす。これは、系列(1, 3, null, 2)を合蚈する必芁がありたす。 圌女が空の倀を考慮するず、次の䞀連のアクションが埗られたす。
1 + 3 = 4; 4 + null = null; null + 2 = null 1 + 3 = 4; 4 + null = null; null + 2 = null 。
おそらくこれを取埗したくないため、集蚈を蚈算するずきにこのような蚈算に満足するこずはたずありたせん。 そしお、デヌタりェアハりスの建蚭に䌎うhemo栞はどうなるのでしょうか... Brrrrr ...

デヌタ付きのテヌブル。 以䞋で䜕床も䜿甚されたす
 create table agg( id int, n int ); insert into agg values( 1, 1 ); insert into agg values( 2, 3 ); insert into agg values( 3, null ); insert into agg values( 4, 2 ); commit; 

NULL倀は集玄によっお無芖されたす。
 select sum(n) from agg; -- 6 

COUNT行カりント関数は、 COUNT(*)たたはCOUNT()の圢匏で䜿甚される堎合、空の倀を考慮したす。 ただし、 COUNT()圢匏で䜿甚される堎合、空の倀は無芖されたす。

定数付き
 select count(*) from agg; -- 4 select count(1+1) from agg; -- 4 select count(user) from agg; -- 4 

匏あり
 select count(n) from agg; -- 3 select count(id) from agg; -- 4 select count(abs(n)) from agg; -- 3 

たた、 AVGなどの機胜にも泚意しおください。 空の倀を無芖するため、フィヌルドN結果は(1+3+2)/3であり、 (1+3+2)/4はありたせん。 おそらく、このような平均の蚈算は必芁ありたせん。 このような問題を解決するには、暙準的な解決策がありたすNVL関数を䜿甚したす
 select avg(n) from agg; -- (1 + 3 + 2) / 3 = 2 select avg(nvl(n,0)) from agg; -- (1 + 3 + 0 + 2) / 4 = 1.5 

集蚈関数は、空のデヌタセットに適甚される堎合、たたはNULLのみで構成される堎合、 返したす。 䟋倖は、行数をカりントするためのREGR_COUNTおよびCOUNT()関数REGR_COUNT 。 䞊蚘の堎合、れロを返したす。

NULLのみのデヌタセット
 select sum(n) from agg where n is null; --  select avg(n) from agg where n is null; --  select regr_count(n,n) from agg where n is null; -- 0 select count(n) from agg where n is null; -- 0 

空のデヌタセット
 select sum(n) from agg where 1 = 0; --  select avg(n) from agg where 1 = 0; --  select regr_count(n,n) from agg where 1 = 0; -- 0 select count(n) from agg where 1 = 0; -- 0 

OLAPのNULL


ナニットに関連付けられおいる別の機胜に぀いお簡単に説明したす。 ク゚リの結果ずしおの倚次元NULLキュヌブでは、デヌタの欠劂ずディメンションによるグルヌプ化の兆候の䞡方を意味する堎合がありたす。 最もうんざりするこずは、これらの2぀の䜎血圧症を芖芚で区別できないこずです。 幞いなこずに、より鋭い目を持぀特別なGROUPINGおよびGROUPING_ID関数がありたす。 GROUPING()は、ディメンション列のNULLがこの列によるグルヌプ化の蚘号を意味する堎合は1を返し、特定の倀特にNULLが含たれる堎合は0を返したす。 GROUPING_ID関数はGROUPING_IDからのビットベクトルです。このノヌトでは、これは間違いなく䞍芁です。

䞀般に、倚倉量解析におけるNULL二元性に関するこのような簡朔で無秩序な情報。 以䞋は、 GROUPINGの䜿甚䟋であり、Wellcome Data Warehousing Guideの第21章の詳现です。

䟿利な機胜sqlplusデヌタを出力するずき、指定された文字列でNULLを眮き換えたす
 set null [NULL] 

倚次元キュヌブのNULL双察性の確認
 with t as ( --   1  select 'IVAN' customer, 'KEFIR' product, 1 qty from dual union all --    2  select NULL customer, 'MOLOKO' product, 2 qty from dual union all --   2  select 'IVAN' customer, 'MOLOKO' product, 2 qty from dual ) select customer cust, grouping(customer) grp_c , product prod, grouping(product) grp_p , sum(qty) qty from t group by cube(customer, product) order by grp_c, grp_p; CUST GRP_C PROD GRP_P QTY ---- ----- ------ ----- ---- [NULL] 0 MOLOKO 0 2 --    2   IVAN 0 KEFIR 0 1 --   1   IVAN 0 MOLOKO 0 2 --   2   IVAN 0 [NULL] 1 3 --   3    [NULL] 0 [NULL] 1 2 --    2    [NULL] 1 MOLOKO 0 4 --    4   [NULL] 1 KEFIR 0 1 --    1   [NULL] 1 [NULL] 1 5 --    5    


舞台裏に残っおいるもの


それはかなり長いこずが刀明したため、情報の䞀郚を切り取らなければなりたせんでした。 すなわち
著者の無胜に察する批刀、远加、およびほのめかしを文曞を参照しお歓迎したす。 実際、このためにすべおが開始されたした。

Source: https://habr.com/ru/post/J127327/


All Articles