MySQL 更新セットとの違い

MySQL 更新セットとの違い

問題の説明

最近、奇妙な問い合わせを受けました。更新ステートメントはエラーなく実行されたのですが、データが更新されませんでした。問題のある具体的なステートメントは次のようなものでした。

test.stu を更新し、cname = '0'、math = 90、his = 80、id = 100 に設定します。

原因分析

直感的に、この更新ステートメントの構文には問題があります。複数のデータ列を更新するための通常の構文では、次の形式のようにカンマを使用する必要があります。

test.stu を更新し、cname = '0'、math = 90、his = 80、id = 100 に設定します。

と を直接使用した場合の最初の反応は、実際には構文エラーが報告され、正常に実行できないように見えることです。次に、Tencent Cloud Database MySQL に基づいて、実際に簡単なシナリオを構築し、この問題を再現してみます。

SQL ステートメントは次のとおりです。

テーブル `stu` を作成します (
  `id` int(11) NULLではない、
  `sname` varchar(16) NOT NULL,
  `cname` varchar(8) デフォルト NULL,
  `math` int(11) NOT NULL,
  `eng` int(11) デフォルト NULL,
  `his` int(11) デフォルト NULL,
  主キー (`id`)
)ENGINE=InnoDB デフォルト文字セット=utf8mb4;

stu に値 (100,'sam','0',90,88,83) を挿入します。
stu に値 (101,'jhon','1',97,82,81) を挿入します。
stu に値 (102,'mary','2',87,89,92) を挿入します。
stu に値 (103,'adam','2',87,89,92) を挿入します。

次に、通常の更新ステートメントと、およびを使用した更新ステートメントを試して、実際の実行結果を確認します。

mysql> 開始します。
クエリは正常、影響を受けた行は 0 行 (0.00 秒)

mysql> test.stu を更新し、cname = '0'、math = 90、his = 80、id = 100 に設定します。
クエリは正常、影響を受けた行は 0 行 (0.00 秒)
一致した行: 1 変更: 0 警告: 0

mysql> stu から * を選択します。
+-----+-------+-------+------+------+------+
| id | sname | cname | math | eng | his |
+-----+-------+-------+------+------+------+
| 100 | サム | 0 | 90 | 88 | 83 |
| 101 | ジョン | 1 | 97 | 82 | 81 |
| 102 | メアリー | 2 | 87 | 89 | 92 |
| 103 | アダム | 2 | 87 | 89 | 92 |
+-----+-------+-------+------+------+------+
セット内の 4 行 (0.00 秒)

mysql> test.stu を更新し、cname = '0'、math = 90、his = 80、id = 100 に設定します。
クエリは正常、1 行が影響を受けました (0.01 秒)
一致した行: 1 変更された行: 1 警告: 0

mysql> stu から * を選択します。
+-----+-------+-------+------+------+------+
| id | sname | cname | math | eng | his |
+-----+-------+-------+------+------+------+
| 100 | サム | 0 | 90 | 88 | 80 |
| 101 | ジョン | 1 | 97 | 82 | 81 |
| 102 | メアリー | 2 | 87 | 89 | 92 |
| 103 | アダム | 2 | 87 | 89 | 92 |
+-----+-------+-------+------+------+------+
セット内の 4 行 (0.00 秒)

mysql> ロールバック;
クエリは正常、影響を受けた行は 0 行 (0.01 秒)

マイSQL>

どちらのステートメントもエラーを報告せず、更新ステートメントは特定の行と一致しますが (一致した行数: 1)、データは変更されません (変更: 0)。標準構文の更新ステートメントは、通常どおりデータを変更します。

これは、MySQL が and の使用を文法的に間違っているとは見なしていないことを示しています。つまり、MySQL はこのステートメントを別の方法で「解釈」します。最も簡単に考えられるのは、設定時に MySQL が英語の意味での「and」ではなく論理演算子として「and」を解釈するかどうかです。さらに、cname の値は元々 0 であり、これは bool データを処理するときのデータベースの動作と一致しています (False と True の代わりに 0 と 1 を使用します)。

検証は非常に簡単です。異なる cname 値でデータを更新するだけです。

mysql> stu から * を選択します。
+-----+-------+-------+------+------+------+
| id | sname | cname | math | eng | his |
+-----+-------+-------+------+------+------+
| 100 | サム | 0 | 90 | 88 | 83 |
| 101 | ジョン | 1 | 97 | 82 | 81 |
| 102 | メアリー | 2 | 87 | 89 | 92 |
| 103 | アダム | 2 | 87 | 89 | 92 |
+-----+-------+-------+------+------+------+
セット内の 4 行 (0.00 秒)

mysql> begin;update test.stu を設定し、cname = '0'、math = 90、his = 80、id = 101 を設定します。
クエリは正常、影響を受けた行は 0 行 (0.00 秒)

クエリは正常、1 行が影響を受けました (0.00 秒)
一致した行: 1 変更された行: 1 警告: 0

mysql> stu から * を選択します。
+-----+-------+-------+------+------+------+
| id | sname | cname | math | eng | his |
+-----+-------+-------+------+------+------+
| 100 | サム | 0 | 90 | 88 | 83 |
| 101 | ジョン | 0 | 97 | 82 | 81 |
| 102 | メアリー | 2 | 87 | 89 | 92 |
| 103 | アダム | 2 | 87 | 89 | 92 |
+-----+-------+-------+------+------+------+
セット内の 4 行 (0.00 秒)

mysql> ロールバック;
クエリは正常、影響を受けた行は 0 行 (0.00 秒)

結果から、MySQL が cname の値を 0 に変更していることがわかります。これは、それが実際に論理演算子として扱われていることを意味します。このステートメントを注意深く分析すると、MySQL が次のように処理していることがわかります。

cname = ('0'、math = 90、his = 80) を設定します。

math と his の値は、where 条件によってフィルタリングされた行によって決定されます。上記のテスト シナリオでは、次の論理的判断が行われます。

'0' と 97 = 90 と 81 = 80

PS: 文字データ 0 であっても False として扱われることに注意してください。

解決

現在、sql_mode やその他のパラメータを使用して「and」を使用したこのタイプの更新ステートメントを防ぐことはできないため、このタイプの問題は比較的目立たない状態になっています。開発中にこの問題を回避するには、カプセル化されたフレームワークを使用するか、コードまたは SQL レビューを強化することをお勧めします。

PS: Tencent Cloud Database MySQL にも同様の問題が発生するため、注意してください。

上記は、MySQL アップデート セットとの違いの詳細内容です。MySQL アップデート セットとの詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • 実用的な MySQL + PostgreSQL バッチ挿入更新 insertOrUpdate
  • MySQL UPDATE ステートメントの非標準実装コード
  • mysql 更新ケース更新フィールド値が固定されていない操作
  • Mysql 更新マルチテーブル共同更新方法の概要
  • 更新とデータ整合性処理のためのMySQLトランザクション選択の説明
  • MySQL UPDATE ステートメントの「典型的な」落とし穴

<<:  HTML メタタグの小さなコレクション

>>:  Window.nameはクロスドメインデータ転送の問題を解決します

推薦する

HTML ul および li タグを使用して画像を表示するサンプル コード

以下のコードをDreamweaverのコードエリアにコピーすると、プレビュー時に以下の画像が表示され...

HTMLでキーワードを強調表示するのに最適なソリューション

最近、プロジェクトに取り組んでいるときに、Web ページ上のキーワードを強調表示する機能に遭遇しまし...

Docker デプロイメント Springboot プロジェクト例の分析

この記事は主に、docker デプロイメント springboot プロジェクトのサンプル分析を紹介...

Linux でも利用できる人気の Windows アプリ 10 選

データ分析会社Net Market Shareによると、Linuxデスクトップオペレーティングシステ...

DockerHubを自分で構築する方法

先ほど使用したDocker HubはDockerによって提供されています。独自のDockerを構築す...

Dockerでの接続例外中のエラーを解決する

Docker を初めて使い始めると、通常とは異なる問題に遭遇して、必然的に混乱してしまいます。大丈夫...

Linux仮想マシンの静的IPアドレスを構成するための手順を完了します

序文多くの場合、仮想マシンを使用します。たとえば、一部のテストは検出されません。何かを壊すことを心配...

MySQLインスタンスを安全にシャットダウンする方法

この記事では、mysqld プロセスをシャットダウンするプロセスと、MySQL インスタンスを安全か...

Vue が Ref を使用してレベル間でコンポーネントを取得する手順

VueはRefを使用してレベル間でコンポーネントインスタンスを取得します例の紹介開発プロセスでは、レ...

Dockerは元のタグのイメージの再タグ付けと削除を実装します

docker イメージ ID は一意であり、イメージを物理的に識別できます。repository: ...

RGBカラーテーブルコレクション

RGBカラーテーブル色英語名RGB 16色雪255 250 250 #FFFAFAゴーストホワイト2...

Vue+ElementUI はページング関数を実装します - mysql データ

目次1. 問題2. 解決策2.1 ページングコンポーネント2.2 データベースデータを取得する関数:...

HTMLのmarquee属性でテキストを踊らせる

構文: <marquee> …</marquee>モバイル属性マーキーを使用...

HTML で 2 つの div タグの間に垂直線を描く方法

最近、インターフェースを描画しているときに、インターフェースに垂直線を描画し、この垂直線の高さが親 ...

JavaScriptプロトタイプチェーン図のまとめと実践

目次プロトタイプチェーンプロトタイプチェーンに基づいてシンプルなJQueryライブラリを実装すること...