MySQLクエリ条件のnot inとinの違いと理由

MySQLクエリ条件のnot inとinの違いと理由

まずSQLを書く

SELECT DISTINCT from_id
タラから
cod.from_id が (37, 56, 57) に含まれない場所

今日 SQL を書いていたところ、クエリ結果が不完全で、NULL 値が欠落しており、さらに存在しない場合は null が除外されていることに気付きました。

inを使用する場合、nullは含まれません

MySQL は適切に設計されていないように感じます。

なぜなら、in と not in は互いに補完し合うべきだと私は常に思っていたからです。検索全体は次のようになるはずです。

SELECT DISTINCT from_id
タラから
cod.from_id が (37, 56, 57) ではない、または cod.from_id が (37, 56, 57) である

結果は予想通りで、nullが欠落しています

後でオンラインで調べたところ、合理的な説明が見つかりました。

nullはどの値と比較しても偽である

たとえば、from_id が (37, 56, 57,28,null) の場合、28 と比較すると not in (37, 56, 57) は true なので、結果セットには 28 が表示されます。

null を条件 not in (37, 56, 57) と比較すると、結果は false となるため、結果セットには表示されません。

補足:MySQL条件クエリINとNOT INの両側でNULL値を処理する方法

トピック

テーブル ツリーの場合、id はツリー ノードの番号であり、p_id はその親ノードの ID です。

+----+------+

| id | p_id |

+----+------+

| 1 | NULL |

| 2 | 1 |

| 3 | 1 |

| 4 | 2 |

| 5 | 2 |

+----+------+

ツリー内の各ノードは、次の 3 つのタイプのいずれかになります。

リーフ: このノードに子ノードがない場合。

ルート: このノードがツリー全体のルートである場合、つまり親ノードがない場合。

内部ノード: ノードがリーフ ノードでもルート ノードでもない場合。

すべてのノードの数とタイプを出力するクエリ ステートメントを記述し、結果をノード番号で並べ替えます。上記の例の結果は次のようになります。

+----+------+

| id | タイプ |

+----+------+

| 1 | ルート |

| 2 | 内側|

| 3 | 葉 |

| 4 | 葉 |

| 5 | 葉 |

+----+------+

説明する

ノード '1' は親が NULL であり、子ノード '2' と '3' を持つため、ルート ノードです。

ノード「2」は親ノード「1」を持ち、子ノード「4」と「5」も持っているため、内部ノードです。

ノード「3」、「4」、および「5」は親ノードを持ち、子ノードがないため、リーフノードです。

この例のツリーは次のようになります。

 1

 / \\

 23

 / \\

 4 5

まずテーブルを作成する

1. テーブルを作成する

テーブルツリーの作成(
id INT 、
p_id 整数 
)

やり方は次のとおりです:

SELECT id,(
場合 
 tree.p_id が NULL の場合、'Root'
 WHEN tree.id NOT IN ( -- id が親ノードの p_id 列にない場合は、論理的に正しいリーフノードと見なされます。
 p_idを選択
 木から
 GROUP BY p_id
 )そして「葉」
 ELSE「内側」
終わり
)タイプ
木から

親ノードの p_id 列に id がない場合、リーフ ノードと見なされると思います。論理的にはまったく問題はありません。ただし、物事はそれほど単純ではありません。クエリ結果は次のとおりです。id=3 から始めて、必要な結果が見つかりませんでした。すごいですね!

そしてもう一晩経って、ついに問題を解決しました。まずは正しいアプローチを紹介します。

SELECT id,(
場合 
 tree.p_id が NULL の場合、'Root'
 tree.id が ( に含まれない ) の場合
 p_idを選択
 木から
 WHERE p_id IS NOT NULL -- SQL文を追加しました
 GROUP BY p_id
 )そして「葉」
 ELSE「内側」
終わり
)タイプ
木から

なぜこのようなことが起こるのでしょうか?

周知された

MySQL の IN 演算子は、式の値が指定されたリスト内にあるかどうかを判断するために使用されます。リスト内にある場合、戻り値は 1 になり、それ以外の場合は戻り値は 0 になります。

NOT IN の機能は IN と正反対です。NOT IN は、指定されたリストに式の値が存在しないかどうかを判断するために使用されます。存在しない場合は戻り値は 1 になり、存在する場合は戻り値は 0 になります。

これが私たちが通常使用する方法であり、結果は私たちが望んでいる通りです。しかし、次のような特殊な状況に遭遇することがよくあります。

(1)inまたはnot inのどちらの側にもNULL値は存在しない

[例 1] SQL 文で IN 演算子と NOT IN 演算子を使用する:

mysql> SELECT 2 IN (1,3,5,'thks'),'thks' IN (1,3,5, 'thks');
+---------------------+---------------------------+
| 2 IN (1,3,5,'thks') | 'thks' IN (1,3,5, 'thks') |
+---------------------+---------------------------+
| 0 | 1 |
+---------------------+---------------------------+
セットに 1 行、警告 2 件 (0.00 秒)

mysql> SELECT 2 NOT IN (1,3,5,'thks'),'thks' NOT IN (1,3,5, 'thks');
+-------------------------+-------------------------------+
| 2 は (1,3,5,'thks') に含まれません | 'thks' は (1,3,5, 'thks') に含まれません |
+-------------------------+-------------------------------+
| 1 | 0 |
+-------------------------+-------------------------------+
セットに 1 行、警告 2 件 (0.00 秒)

結果から、IN と NOT IN の戻り値がまったく逆であることがわかります。

しかし、私はNULL値の問題を無視しました

NULL値の取り扱い

IN 演算子のいずれかの側が NULL の場合、一致するものが見つからない場合、戻り値は NULL になります。一致するものが見つかった場合、戻り値は 1 になります。

(2)NULL値はinの両側にある

次の SQL ステートメントを参照してください。

mysql> SELECT NULL IN (1,3,5,'thks'),10 IN (1,3,NULL,'thks');
+------------------------+-------------------------+
| NULL IN (1,3,5,'thks') | 10 IN (1,3,NULL,'thks') |
+------------------------+-------------------------+
| NULL | NULL |
+------------------------+-------------------------+
セットに 1 行、警告 1 件 (0.00 秒)

mysql> SELECT NULL IN (1,3,5,'thks'),10 IN (1,10,NULL,'thks');
+------------------------+---------------------------+
| NULL IN (1,3,5,'thks') | 10 IN (1,10,NULL,'thks') |
+------------------------+--------------------------+
| NULL | 1 |
+------------------------+--------------------------+
セット内の 1 行 (0.00 秒)

(3)NOT INの片側がNULL

NOT IN は正反対です。NOT IN 演算子の 2 つの辺のうちの 1 つが NULL 値 NULL の場合、一致するものが見つからない場合は戻り値は NULL になり、一致するものが見つかった場合は戻り値は 0 になります。

次の SQL ステートメントを参照してください。

mysql> SELECT NULL NOT IN (1,3,5,'thks'),10 NOT IN (1,0,NULL,'thks');
+----------------------------+----------------------------+
| NULL は (1,3,5,'thks') に含まれません | 10 は (1,0,NULL,'thks') に含まれません |
+----------------------------+----------------------------+
| NULL | NULL |
+----------------------------+----------------------------+
セットに 1 行、警告 1 件 (0.00 秒)

mysql> SELECT NULL NOT IN (1,3,5,'thks'),10 NOT IN (1,10,NULL,'thks');
+----------------------------+------------------------------+
| NULL は (1,3,5,'thks') に含まれません | 10 は (1,10,NULL,'thks') に含まれません |
+----------------------------+------------------------------+
| NULL | 0 |
+----------------------------+------------------------------+
セット内の 1 行 (0.00 秒)

(3)NOT INの片側がNULLであることから、問題が分かります。

まず次のSQL文をクエリして、ゆっくりと問題を見つけてみましょう。

p_idを選択
木から
GROUP BY p_id

上記のクエリ結果にはNULL値が含まれています

したがって、次のSQL文はNOT INがNULLを返すため、何も見つかりません。

選択ID 
木から
id が ( に含まれない )
 p_idを選択
 木から
 GROUP BY p_id
 )

したがって、結果を照会する場合は、まず NULL 値を処理する必要があります。はい、バグは修正されました!

この問題を解く別の方法があります:

SELECT id,(
場合 
 tree.p_id が NULL の場合、'Root'
 tree.idがIN(
 p_idを選択
 木から
 GROUP BY p_id
 )そして「内側」
 ELSE「葉」
終わり
)タイプ
木から

なぜそれが正しいのでしょうか?それは皆さんに考えさせてください〜

上記は私の個人的な経験です。参考になれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。間違いや不備な点がありましたら、遠慮なくご指摘ください。

以下もご興味があるかもしれません:
  • MySQLはクエリ条件としてJSONフィールドの内容に基づいてデータを取得します(JSON配列を含む)
  • Mysqlクエリ条件で文字列の末尾にスペースがあっても一致しない問題の詳細な説明
  • MySQLクエリ条件の一般的な使用法の詳細な説明
  • インデックスは MySQL クエリ条件で使用されますか?
  • MySQLクエリ条件におけるonとwhereの配置の違いの分析
  • MySQLはクエリ条件を最適化する方法を説明しています

<<:  カルーセル効果を作成するためのjs

>>:  XHTML チュートリアル、XHTML の基礎を簡単に紹介します

推薦する

DockerはPruneコマンドを使用してnoneイメージをクリーンアップします

目次無イメージの創造と混乱Noneオブジェクトをクリーンアップする方法トリムミラーコンテナで使用され...

LAMP ソースコードを使用したエンタープライズレベルのインストールチュートリアル

目次LAMPアーキテクチャ1.ランプの紹介2. WebサービスワークフローWebサーバーのリソースは...

WeChat ミニプログラム ユーザー認証のベストプラクティス ガイド

序文WeChat アプレットを開発する際には、ユーザーの権限が必要なページを使用する必要があることが...

Linux Cron によるパラメータ付き PHP コードのスケジュール実行

1. 引き続き PHP スクリプトを使用して実行します。コマンドラインに入力: php /home/...

Vueの計算プロパティの詳細な説明

1. 計算属性とは何ですか? 簡単に言えば、計算された結果が属性に保存されるもので、キャッシュとして...

Dockerが新しいイメージをロードした後にリポジトリとタグ名が両方ともnoneになる問題を解決する

次のコマンドを使用できます: docker tag [イメージID] [名前]:[バージョン]例えば...

vue+echartsチャートの使用に関する問題記録

序文echarts は私が最もよく使用するチャート作成ツールであり、非常に完全なエコシステムとコンテ...

Spark と Scala を使用して Apache アクセス ログを分析する方法

インストールまず、Java と Scala をインストールし、次に Spark をダウンロードしてイ...

40以上の美しいWebフォームデザイン例

Web フォームは、訪問者と Web サイト所有者間の主要なコミュニケーション チャネルです。フィー...

カルーセル効果を書くためのjs

この記事では、カルーセルマップの効果を実現するためのjsの具体的なコードを参考までに共有します。具体...

MySQL 8.0.24 のインストールと設定方法のグラフィックチュートリアル

この記事では、MySQL 8.0.24のインストールチュートリアルを参考までに紹介します。具体的な内...

MySQL innodb B+ツリーの高さを取得する方法

序文MySQL の InnoDB エンジンがインデックスの保存に B+tree を使用する理由は、デ...

HTML ウェブページ作成のための 8 つの強力なテクニック

<br />作業を簡単に完了できる Web ページ作成ツールは数多くありますが、HTML...

MySQL InnoDB のトランザクション特性を確保するにはどうすればよいですか?

序文「データベース トランザクションの特徴は何ですか?」と尋ねられたら、 ACID 特性である原子性...

JDBC を MySQL 5.7 に接続する方法

1. まずMySQLとEclipseの環境を準備します。環境がセットアップされたら、Eclipseの...