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はクロスドメインデータ転送の問題を解決します

推薦する

CSS でよく使用されるフォントサイズ、フォント単位、行の高さの詳細な説明

px(ピクセル)ピクセルという言葉は皆さんもよくご存知だと思います。次に、この単位に関するちょっとし...

Vue は Websocket カスタマー サービス チャット機能を実装します

この記事では主に基本的なチャットの実装方法を紹介します。今後は絵文字や写真のアップロードなどの機能も...

resizeを使用して画像切り替えプレビュー機能を実装する方法

要点CSS resize プロパティを使用すると、要素のサイズ変更可能性を制御できます。サイズ変更を...

HTML はモバイル上で固定フローティング半透明検索ボックスを実装します

質問。モバイルショッピングモールシステムでは、ページの上部に検索ボックスがよく見られます。ブロガーは...

HTML での非同期ファイルアップロードの例

コードをコピーコードは次のとおりです。 <form action="/hehe&qu...

MySQLのグローバルロックとテーブルロックに関する詳細な理解

序文ロックの範囲に応じて、MySQL のロックは、グローバル ロック、テーブル ロック、行ロックに大...

MySQLストアドプロシージャを変更する詳細な手順

序文実際の開発では、ビジネス要件が変更されることが多いため、ストアド プロシージャの特性を変更するこ...

MySQL json 形式のデータクエリ操作

デフォルトのテーブル名はbase_dataで、json列名はjson_valueです。 json_v...

MySQL 5.7.18 バージョンの無料インストール構成チュートリアル

MySQLはインストール版と無料インストール版に分かれていますインストール版の拡張子はmsi、無料イ...

MySQL の 4 つのトランザクション分離レベルの詳細な説明

この実験のテスト環境: Windows 10+cmd+MySQL5.6.36+InnoDB 1. ト...

Docker を使用した war パッケージ プロジェクトのデプロイの実装

Docker で war をデプロイするには、コンテナを使用する必要があります。ここでは tomca...

Windows での MySQL の使用: 自動スケジュールバックアップの実装

1. バックアップスクリプトを書く 著者:www.yumi-info.com 日付:20171222...

MySQL が my.cnf を読み込む順序の詳細

目次MySQLがmy.cnfを読み込む順序1. mysql.server の起動方法2. mysql...

ブリージングカルーセルを実装するネイティブJS

今日は、ネイティブ JS で実装されたブリージング カルーセルを紹介します。効果は次のとおりです。 ...

JavaScript ベースのシンプルな計算機の実装

この記事では、参考までに、簡単な計算機を実装するためのJavaScriptの具体的なコードを紹介しま...