MySQLのROUND関数の丸め演算における落とし穴の分析

MySQLのROUND関数の丸め演算における落とし穴の分析

この記事では、MySQL の ROUND 関数を使用した丸め操作の落とし穴を例を使って説明します。ご参考までに、詳細は以下の通りです。

MySQL では、クエリ結果を丸めるためにROUND関数が使用されます。しかし、最近、 ROUND関数を使用して結果を丸めると、期待どおりに動作しないことがわかりました。この記事では、他のユーザーが私と同じ間違いをしないように、この問題を記録します。

問題の説明

データテーブルテストがあるとします。テーブル作成ステートメントは次のようになります。

CREATE TABLEテスト(
 id int(11) NOT NULL AUTO_INCREMENT、
 フィールド1 bigint(10) デフォルト NULL,
 フィールド2 10進数(10,0) デフォルト NULL、
 フィールド3 int(10) デフォルト NULL,
 フィールド4 float(15,4) デフォルト NULL,
 フィールド5 float(15,4) デフォルト NULL,
 フィールド6 float(15,4) デフォルト NULL,
 主キー (id)
)ENGINE=InnoDB デフォルト文字セット=utf8;

id フィールドの他に、異なるデータ型の複数のフィールドを含む test という名前のテーブルを作成しました。このテーブルにデータを挿入してみましょう。

INSERT INTO テスト (フィールド1、フィールド2、フィールド3、フィールド4、フィールド5、フィールド6) VALUE (100、100、100、1.005、3.5、2.5);

挿入後、テーブル内のデータは次のようになります

mysql> テストから * を選択します。
+----+---------+---------+---------+--------+--------+--------+
| id | フィールド1 | フィールド2 | フィールド3 | フィールド4 | フィールド5 | フィールド6 |
+----+---------+---------+---------+--------+--------+--------+
| 1 | 100 | 100 | 100 | 1.0050 | 3.5000 | 2.5000 |
+----+---------+---------+---------+--------+--------+--------+
セット内の 1 行 (0.00 秒)

今、次の SQL を実行すると、結果はどうなると思いますか?

選択
 round(フィールド1 * フィールド4)、
 round(フィールド2 * フィールド4)、
 ラウンド(フィールド3 * フィールド4)、
 丸め(フィールド1 * 1.005)、
 丸め(フィールド2 * 1.005)、
 丸め(フィールド3 * 1.005)、
 ラウンド(フィールド5)、
 ラウンド(フィールド6)
テストから;

最初は、上記の 6 つの値はすべて 100 * 1.005 に丸められるため、結果は 101 になり、最後の 2 つは 4 と 3 になるはずだと考えていました。しかし、最終結果は予想とはまったく異なります。

************************** 1. 行 ****************************
丸め(フィールド1 * フィールド4): 100
丸め(フィールド2 * フィールド4): 100
丸め(フィールド3 * フィールド4): 100
 ラウンド(フィールド1 * 1.005): 101
 ラウンド(フィールド2 * 1.005): 101
 ラウンド(フィールド3 * 1.005): 101
    ラウンド(フィールド5): 4
    ラウンド(フィールド6): 2
セット内の 1 行 (0.00 秒)

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

同じ 100*1.005 ですが、データベース内のフィールドを乗算した結果が、フィールドと小数を直接乗算した結果と異なるのはなぜですか?

この問題を解決する方法がわかりません。Baidu や Google で検索しましたが、役に立ちませんでした。 。 。自分に頼るしか方法はありません。このとき最も役立つのは、公式 Web サイトのドキュメントです。そこで、ROUND 関数に関する公式 MySQL ドキュメントを検索したところ、次の 2 つのルールが含まれていました。

  • 正確な数値の場合、ROUND() は「半分を切り上げる」ルールを使用します
  • 近似値の数値の場合、結果は C ライブラリに依存します。多くのシステムでは、これは ROUND() が「最も近い偶数に丸める規則を使用することを意味します。つまり、小数部を持つ値は、最も近い偶数にROUNDます。(近似値の場合、基礎となる C 関数ライブラリに依存します。多くのシステムでは、ROUND 関数は「最も近い偶数に丸める」規則を使用します)

これら 2 つの規則から、2 つのフィールドを乗算すると、最終結果はfloat型に従って処理され、 float型はコンピューター内の正確な数値ではないため、処理結果は 2 番目の規則に従って処理されることがわかります。直接整数フィールドの結果と 1.005 などの小数演算は、演算に関係する 2 つの値が正確な数値であるため、最初の規則に従って計算されます。 field5 と field6 に対してROUND関数を実行した結果から、実際に最も近い偶数に変換されていることが明確にわかります。

要約する

この例から、MySQL でROUNDを使用する場合は特に注意する必要があることがわかります。特に、計算に関係するフィールドに浮動小数点数が含まれている場合は、計算結果が不正確になります。

MySQL 関連のコンテンツに興味のある読者は、このサイトの次のトピックをチェックしてください: 「MySQL クエリ スキル」、「MySQL トランザクション操作スキル」、「MySQL ストアド プロシージャ スキル」、「MySQL データベース ロック関連スキルの概要」、および「MySQL 共通関数の概要」

この記事が皆様のMySQLデータベース設計に役立つことを願っています。

以下もご興味があるかもしれません:
  • MySQL Where 条件文の紹介と演算子の概要
  • MySQLで使用される演算子の例
  • MySQL ノート: 演算子の使用法の詳細な説明
  • mySQL UNION演算子のデフォルトルールの研究
  • PHP MySQL アプリケーションで XOR 暗号化アルゴリズムを使用する
  • MSSQL との比較で MYSQL を学ぶ (V) - 演算子
  • MySQLでよく使われる演算子と関数の概要
  • MySQL 文字列長計算実装コード (gb2312+utf8)
  • MySQL の重要なパフォーマンス インデックスの計算と最適化方法の概要

<<:  アニメーション効果のようなVueトランジションの例

>>:  Linuxプロセス監視と自動再起動の簡単な実装方法

推薦する

Ubuntu でディスク容量不足により MySQL が起動しない場合の解決策

序文最近、データベースのテーブルに 2 つのフィールドを追加しました。その後、ディスク容量不足のよう...

プロジェクトのフロントエンドとバックエンドでの Echart チャートの使用に関する詳細な説明

目次序文1. プロジェクトアーキテクチャ2. Echart公式サイトにアクセスして自己分析を学ぶ2....

Mysql ファジークエリが大文字と小文字を区別するかどうかの詳細な調査

序文最近、私は小さな個人ブログ プロジェクトを書くのに忙しくしています。 「グローバル検索」機能を実...

vue3 を使用してカウント関数コンポーネントのカプセル化例を実装する

目次序文1. カプセル化の重要性2. どのようにカプセル化しますか? 1. アイデア2. 準備2. ...

レスポンシブなカードホバー効果を実現するための HTML+CSS

目次成し遂げる:要約:言うことはあまりありませんが、まずは効果を見てみましょう。 カードホバー、レス...

Linux C++ マルチスレッド同期の非常に詳細な説明

目次1. ミューテックス1. ミューテックスの初期化2. ミューテックスロックの関連特性と分類3. ...

Dockerのセキュリティについて Docker-TLS暗号化通信の問題

目次1. Dockerのセキュリティ問題2. Dockerアーキテクチャの欠陥とセキュリティメカニズ...

Linux での MySql centos7 のバイナリコンパイルとインストールに関するチュートリアル

// これをインストールするのに丸一日かかったので、記録するためにメモを書きました。 //何か問題が...

FileZilla_Server:425 データ接続を開けない問題を解決する方法

FileZilla Serverをサーバーにインストールすると、425データ接続を開けない問題が発生...

Vue の foreach 配列と js の traversal 配列の書き方の説明

Vue foreach配列を記述し、jsで配列をトラバースする方法シナリオVueでAxiosを使用し...

Linux システムで TCP 接続を作成するプロセスの紹介

目次LinuxでTCPを作成する手順サーバクライアントTCP確立プロセスサンプルコードLinuxでT...

jQueryは記事の折りたたみと展開の機能を実装します

この記事の例では、記事の折りたたみと展開の機能を実現するためのjQueryの具体的なコードを参考まで...

MySQL で特定の日、月、または年のデータをクエリするためのコードの詳細な説明

今日 テーブル名から * を選択します。ここで、to_days(時間フィールド名) = to_day...

Linuxは、単一のIPをバインドするためにデュアルネットワークカードを実装するためにボンドを使用します。サンプルコード

ネットワークの高可用性を実現するには、複数のネットワーク カードを仮想ネットワーク カードにバインド...

CSS 変数に基づくテーマ切り替えに最適なソリューション (推奨)

この要件を受け取ったとき、Baidu は、CSS リンクの置き換え、className の変更、le...