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

推薦する

JS でカルーセル画像を実装するいくつかの方法

カルーセル主なアイデアは次のとおりです。大きなコンテナには、コンテナの幅の整数倍の非常に長いテーブル...

CUDA8.0とCUDA9.0はUbuntu16.04で共存します

序文Github にある以前のコードには、CUDA 8.0 環境が必要なものもあります。初心者の場合...

Linux の MySQL でリモート接続を承認する方法

注意: 他のマシン (IP) は、承認なしではクライアント経由で MySQL データベースに接続でき...

Vueタブとキャッシュページを切り替えるいくつかの方法

目次1. 切り替え方法2. タブを動的に生成する3. キャッシュコンポーネント3.1 キープアライブ...

MySQL 学習ノート ヘルプ ドキュメント

システムヘルプを表示help contents mysql> ヘルプコンテンツ; ヘルプ カテ...

Vueはシンプルな虫眼鏡効果を実装します

この記事では、参考までに、簡単な虫眼鏡効果を実現するためのVueの具体的なコードを紹介します。具体的...

SEATAトランザクションサービスDockerのデプロイ手順の詳細説明

1. データベース認証ステートメントを作成する > データベース seata を作成します。 ...

MySQL 8.0 パスワード有効期限ポリシーの詳細な説明

MySQL 8.0.16 以降では、パスワードの有効期限ポリシーを設定できます。今日は、この小さな知...

CSS でレスポンシブ レイアウトを実装する方法

CSS でレスポンシブ レイアウトを実装するレスポンシブレイアウトは非常にハイエンドで難しいように思...

Nodeはkoa2を使用してシンプルなJWT認証方式を実装します

JWT の紹介JWTとは正式名称はJSON Web Tokenで、現在最も人気のあるクロスドメイン認...

JavaScript でシンプルなタイマーを実装する

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

WindowsにOpenSSHをインストールし、SSHキーを生成してLinuxサーバーにログインします。

SSH の正式名称は Secure SHell です。 SSH を使用すると、送信されるすべてのデ...

jQuery タグセレクターの適用例の詳細な説明

この記事では、jQueryタグセレクターアプリケーションの具体的なコードを例として紹介します。具体的...

CSSはラジオをクリックして2つの画像スタイルを切り替えますが、複数のラジオのうち1つだけをチェックできます。

クリックされたボタンには赤い画像スタイルを実装し、選択されていない他のボタンには灰色の画像スタイルを...

初心者向けのHTMLタグネストルールの詳細なまとめ

最近、HTML を再度学習しており、これは HTML に対する新たな理解と言えます。これを過小評価し...