sql >> データベース >  >> RDS >> Oracle

結合条件でISNULLまたはISNOTNULLを使用する-理論上の質問

    テーブルAとBの例:

     A (parent)       B (child)    
    ============    =============
     id | name        pid | name 
    ------------    -------------
      1 | Alex         1  | Kate
      2 | Bill         1  | Lia
      3 | Cath         3  | Mary
      4 | Dale       NULL | Pan
      5 | Evan  
    

    親とその子供を見つけたい場合は、INNER JOINを実行します :

    SELECT id,  parent.name AS parent
         , pid, child.name  AS child
    
    FROM
            parent  INNER JOIN  child
      ON   parent.id     =    child.pid
    

    結果は、parentのすべての一致です のid 左のテーブルとchildから のpid 2番目のテーブルの結果に行として表示されます:

    +----+--------+------+-------+
    | id | parent | pid  | child | 
    +----+--------+------+-------+
    |  1 | Alex   |   1  | Kate  |
    |  1 | Alex   |   1  | Lia   |
    |  3 | Cath   |   3  | Mary  |
    +----+--------+------+-------+
    

    さて、上記は子供がいない親を示していません(彼らのIDは子供のIDと一致しないため、どうしますか?代わりに外部結合を行います。外部結合には、左、右、および3つのタイプがあります。完全な外部結合。左側のテーブル(親)からの「余分な」行が必要なため、左側の結合が必要です。

    SELECT id,  parent.name AS parent
         , pid, child.name  AS child
    
    FROM
            parent  LEFT JOIN  child
      ON   parent.id    =    child.pid
    

    その結果、以前の試合に加えて、試合がない(読む:子供がいない)すべての親も表示されます:

    +----+--------+------+-------+
    | id | parent | pid  | child | 
    +----+--------+------+-------+
    |  1 | Alex   |   1  | Kate  |
    |  1 | Alex   |   1  | Lia   |
    |  3 | Cath   |   3  | Mary  |
    |  2 | Bill   | NULL | NULL  |
    |  4 | Dale   | NULL | NULL  |
    |  5 | Evan   | NULL | NULL  |
    +----+--------+------+-------+
    

    それらすべてのNULLはどこにありましたか から来る?そうですね、MySQL(または使用する可能性のある他のRDBMS)は、これらの親に一致するもの(子)がないため、そこに何を配置するかわかりません。したがって、pidはありません。 また、child.name それらの両親と一致するために。したがって、NULLと呼ばれるこの特別な非値を配置します 。

    私のポイントは、これらのNULLs LEFT OUTER JOIN中に(結果セットに)作成されます 。

    したがって、子供がいない親のみを表示する場合は、WHERE child.pid IS NULLを追加できます。 LEFT JOINへ その上。 WHERE JOINの後に句が評価(チェック)されます 終わらせる。したがって、上記の結果から、pidが存在する最後の3行のみであることが明らかです。 NULLが表示されます:

    SELECT id,  parent.name AS parent
         , pid, child.name  AS child
    
    FROM
            parent  LEFT JOIN  child
      ON   parent.id    =    child.pid
    
    WHERE child.pid IS NULL
    

    結果:

    +----+--------+------+-------+
    | id | parent | pid  | child | 
    +----+--------+------+-------+
    |  2 | Bill   | NULL | NULL  |
    |  4 | Dale   | NULL | NULL  |
    |  5 | Evan   | NULL | NULL  |
    +----+--------+------+-------+
    

    さて、そのIS NULLを移動するとどうなりますか WHEREから確認してください 参加するONに 条項?

    SELECT id,  parent.name AS parent
         , pid, child.name  AS child
    
    FROM
            parent  LEFT JOIN  child
      ON   parent.id    =    child.pid
      AND  child.pid IS NULL
    

    この場合、データベースはこれらの条件に一致する2つのテーブルから行を見つけようとします。つまり、parent.id = child.pidである行 そして child.pid IN NULL 。しかし、そのような一致は見つかりません child.pidがないため 何か(1、2、3、4、または5)と等しく、同時にNULLにすることができます!

    したがって、条件:

    ON   parent.id    =    child.pid
    AND  child.pid IS NULL
    

    と同等です:

    ON   1 = 0
    

    これは常にFalse

    では、なぜ左側のテーブルからすべての行を返すのでしょうか。 LEFT JOINだから! そして、左結合は一致する行(この場合はなし)を返します また、一致しない左側のテーブルの行 チェック(この場合はすべて ):

    +----+--------+------+-------+
    | id | parent | pid  | child | 
    +----+--------+------+-------+
    |  1 | Alex   | NULL | NULL  |
    |  2 | Bill   | NULL | NULL  |
    |  3 | Cath   | NULL | NULL  |
    |  4 | Dale   | NULL | NULL  |
    |  5 | Evan   | NULL | NULL  |
    +----+--------+------+-------+
    

    上記の説明が明確であることを願っています。

    補足(あなたの質問に直接関係していません):なぜ地球上でPanしないのですか? どのJOINにも表示されませんか?彼のpid NULLです SQLの(一般的ではない)ロジックのNULLは何にも等しくないため、親ID(1、2、3、4、および5)のいずれとも一致しません。そこにNULLがあったとしても、NULLsであるため、一致しません。 NULLsでさえも、何にも等しくありません それ自体(それは確かに非常に奇妙な論理です!)。そのため、特別なチェックIS NULLを使用します = NULLではありません チェックしてください。

    したがって、Pan RIGHT JOINを実行すると表示されます ?はい、そうなります! RIGHT JOINは、一致するすべての結果(最初に行ったINNER JOIN)と、一致しないRIGHTテーブルのすべての行(この場合は1つ、(NULL, 'Pan') 行。

    SELECT id,  parent.name AS parent
         , pid, child.name  AS child
    
    FROM
            parent  RIGHT JOIN  child
      ON   parent.id     =    child.pid
    

    結果:

    +------+--------+------+-------+
    | id   | parent | pid  | child | 
    +---------------+------+-------+
    |   1  | Alex   |   1  | Kate  |
    |   1  | Alex   |   1  | Lia   |
    |   3  | Cath   |   3  | Mary  |
    | NULL | NULL   | NULL | Pan   |
    +------+--------+------+-------+
    

    残念ながら、MySQLにはFULL JOINがありません 。他のRDBMSで試すことができ、次のように表示されます:

    +------+--------+------+-------+
    |  id  | parent | pid  | child | 
    +------+--------+------+-------+
    |   1  | Alex   |   1  | Kate  |
    |   1  | Alex   |   1  | Lia   |
    |   3  | Cath   |   3  | Mary  |
    |   2  | Bill   | NULL | NULL  |
    |   4  | Dale   | NULL | NULL  |
    |   5  | Evan   | NULL | NULL  |
    | NULL | NULL   | NULL | Pan   |
    +------+--------+------+-------+
    


    1. SQLサーバーに画像を保存するためだけにJavaScriptを使用して画像をバイト配列に変換するにはどうすればよいですか?

    2. SQLPlus-PL/SQLブロックから複数のファイルへのスプーリング

    3. SQLServerへの接続が機能する場合がある

    4. SQL Serverエラー213:列名または指定された値の数がテーブル定義と一致しません。