0

MySQL の更新は、0123456789 で更新しようとすると、マジック ナンバー 2147483647 で更新されるようです。

どこかで、MySQL は任意のスキーマの INT 列である数値を別の数値に関連付けているようです。そのような協会をどこで探すのでしょうか。詳細は以下の通りです。


この更新は、想定どおりの動作を行い、適切な行の ContactPhone2 列に 012345678 を入力します。

UPDATE `alacarte`.`customercontacts` SET `ContactPhone2`='012345678' WHERE `CustomerID`='cust-000004' and`ContactID`='1'

この更新は、実際には、適切な行の ContactPhone2 列の 2147483647 に入力されます。0123456789 とはかけ離れています。

UPDATE `alacarte`.`customercontacts` SET `ContactPhone2`='0123456789' WHERE `CustomerID`='cust-000004' and`ContactID`='1'

ContactPhone2 のデータ型は INT(10) で、デフォルト値は NULL で、パラメーターは設定されていません (OK、NN、AI など)。これは MYSQL の一般的なログからのものです。012345678 更新の場合。

 130101 17:51:43       89 Query set autocommit=0
 130101 17:51:44       89 Prepare   UPDATE `alacarte`.`customercontacts` SET `ContactPhone2`='012345678' WHERE `CustomerID`='cust-000004' and`ContactID`='1'
       89 Execute   UPDATE `alacarte`.`customercontacts` SET `ContactPhone2`='012345678' WHERE `CustomerID`='cust-000004' and`ContactID`='1'
       89 Query commit
       89 Close stmt

そして、0123456789 更新のログ エントリ。

130101 17:51:48    89 Query set autocommit=0
130101 17:51:49    89 Prepare   UPDATE `alacarte`.`customercontacts` SET `ContactPhone2`='0123456789' WHERE `CustomerID`='cust-000004' and`ContactID`='1'
       89 Execute   UPDATE `alacarte`.`customercontacts` SET `ContactPhone2`='0123456789' WHERE `CustomerID`='cust-000004' and`ContactID`='1'
       89 Query commit
       89 Close stmt

0123456780 で更新するとうまくいきますので、桁数ではありません。

これは、INT(10+) を持つデータベース全体の任意の列で発生しますが、VARCHAR 列では発生しません。

さらに良いのは、コピーして名前を変更した古いスキーマであるthedesignedgeと呼ばれる別のスキーマで同じことを行うことですが、使用されていませんが、まだ mysql でアクティブです。

列で実行されているトリガーはなく、ContactID 列のテーブルで実行されているトリガーは 1 つだけです。エラーも出ません。

クエリは通常、MySQL ワークベンチを介して作成されていますが、ターミナルのシェルを介して更新クエリを直接入力しようとしたことがあり、同じ結果が得られました。

どこかで、MySQL は任意のスキーマの INT 列である数値を別の数値に関連付けているようです。そのような協会をどこで探すのでしょうか。

MySQL のデフォルト設定を除けば、キャッシングやインデックス作成についてはまだ何もしていません。mysql 5.5.29 を実行しています

4

3 に答える 3

2

2147483647 の「マジック」ナンバーは 2^31-1 であり、これは int の上限です。これは、大きすぎる数値を入力したと考えられることを意味します。

最良のオプションは、varchar を使用して電話番号を保存することです。予想されるすべてのケースを処理できる十分な大きさにしてください。正規表現を使用して電話番号をフォーマットし、入力をきれいにすることを強くお勧めします。(xxx) xxx-xxxx のみが必要で、拡張子や面白いもの (国際電話番号など) が必要ない場合に、php で電話番号をフォーマットする簡単な方法を次に示します。

$phoneNumber = '1-(235) 555.1234';

$formatted = '';
if (preg_match('/1?[^0-9]*([02-9][0-9][0-9])[^0-9]*([0-9]{3})[^0-9]*([0-9]{4})/', $phoneNumber, $matches)) {
    $formatted = "($matches[1]) $matches[2]-$matches[3]";
} else {
    // phone number is invalid
}

結果は $formatted = になり(235) 555-1234ます。正規表現には、破棄されるオプションの 1 プレフィックスが含まれており、最初の実際の数値は 1 にはなりません。

明らかに、これと同じ正規表現を使用して電話番号を検証してから、電話番号をフォーマットする場合はそれを受け入れる必要があります。

于 2013-01-02T02:12:35.093 に答える
2

INT 値をオーバーフローしている可能性があります。MySQL がオーバーフローすると、デフォルトでデータ型がサポートする最大値が格納されます。符号付き 32 ビット整数の最大値は 2 31 -1、つまり 2147483647 です。

値「012345678」と「0123456789」は問題ありません。つまり、それらは INT の範囲内にあり、正常に挿入されます。したがって、これらの値が本当に問題を引き起こしているとは思えません。

範囲を超える別の値で更新されている他の SQL ステートメントを探します。たとえば、誰かが内線番号を使用して自分の電話番号を追加しようとした可能性があります。

厳密モードを有効にすると、値を暗黙のうちに切り捨てるのではなく、整数のオーバーフローによってエラーが発生します。それが起こっているとき、それはあなたにもっとはっきりと言うでしょう。

SET SQL_MODE='STRICT_ALL_TABLES';

http://dev.mysql.com/doc/refman/5.5/en/server-sql-mode.htmlを参照してください。

PS: INT(10) は、データ型がサポートする値の範囲にとって整数引数が重要であるかのように言及しています。それはよくある誤解ですが、問題ではありません。INT は常に 32 ビットです。INT(10) と INT(12) の (私のコードに適用されたときの) 違いは何ですか? を参照してください。

于 2013-01-02T02:14:55.487 に答える
1

どのmysqlバージョンを使用していますか? 私はそれを複製することはできません。

set ContactPhone2=round('0123456789')役に立ちますか?(先頭のゼロを保持したい場合は、varchar に変更するだけの方が適切です。)

于 2013-01-02T02:04:42.597 に答える