質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

6回答

28456閲覧

SQLでNULLではなく、0が格納されてしまう。

DaiAoki

総合スコア67

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

1クリップ

投稿2016/10/04 14:24

ユーザーからの入力がなかった場合にはNULLを設定したいのですが、0になってしまいます。
"%s"あたりが怪しいとは思うのですが、どう実装すれば良いか悩んでいます。
現実装は以下に抜粋します。(実際は6カラムありますが、省略しています)
※DBでデータ型はINT、デフォルト値はNULLに設定しています。

php

1$sql = sprintf('INSERT INTO hogeTable SET hoge="%s"', 2 mysqli_real_escape_string($db, $_POST['hoge']) 3);

html

1<td> 2 <select name="hoge"> 3 <option value="">-</option> 4 <option value=1>1</option> 5 <option value=2>2</option> 6 </select> 7</td> 8

「-」を選択して、echo print_r($_POST);で中身を確認すると、空文字が格納されていることが確認できたのですが、
SQL文を生成した際に0に変換されてしまっているようです。

以下のようにしても結果は同じでした。

html

1<td> 2 <select name="hoge"> 3 <option value=NULL>-</option> 4 <option value=1>1</option> 5 <option value=2>2</option> 6 </select> 7</td> 8

取得した値が空文字だった場合、以下のようなSQL文を呼ぶよう分岐することで一応動作上は問題なくなったのですが、かなり強引なやり方なのが気に入りません。

PHP

1$sql = sprintf('INSERT INTO hogeTable SET hoge=NULL');

何か良い方法はありますでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答6

0

ベストアンサー

MySQLでは「INSERT INTO 〜 SET」という構文が使えるんですね・・・ベンダ拡張恐るべし。

前置きはさて置き、
今回のケースではMySQLの自動変換にやられてるくさいですね。

以下、PHPのソースからSQL部分を切り出してみました。

SQL

1INSERT INTO hogeTable SET hoge="%s"

更新しようとしているカラムが数値型ということなので、
上記のSQLに違和感を感じてもらいたい所です。

今回のケースで空文字にした場合も、
value値をNULLに変更してもどちらも0が設定されてしまうのはそれぞれ下記のようなSQLが作成されてしまうためです。

SQL

1-- 空文字の場合 2INSERT INTO hogeTable SET hoge="" 3 4-- valueをNULLにした場合 5INSERT INTO hogeTable SET hoge="NULL" -- ← 文字列「NULL」を設定しようとしてるSQLになる

これにMySQLの無効な文字列は変換できる所までキャストするという動きが相まって「0」が設定されているものと思われます。
(少し旧い記事ですが参考までにこちらをどうぞ)

そもそも数値型データに値を設定する場合は、文字列と異なり引用符は不要です。

なのでvalueをNULLとして、
POST変数にもNULLが文字列として渡っているのであれば、
以下のように引用符を取り外せばNULLとして設定されるはずです。

SQL

1INSERT INTO hogeTable SET hoge= %s

またNULLについては、
扱いが難しいので避けれるのであれば避けてもらうのが無難ですが、
実入力としての「0」は集計対象とする場合は区別化しないと結果が狂うので、
入力内容不明という用途としてNULLを扱う分には頭ごなしには否定しません。

ただし、NULLの特性について熟知した上での利用をお勧めします。
集計関数では原則NULLは除外されるので問題ないですが、
検索条件としての参照や値の比較・計算が発生する場合は要注意です。

蛇足ですがNULLを利用しない代替案としては、
例えばあえて業務上設定されえない値をNULL代わりに利用したり、
入力有無判定ではそれを表すフラグやステータスの列を用意するといった回避策はしばしば使われますね。

投稿2016/10/04 18:17

編集2016/10/04 18:21
Panzer_vor

総合スコア1636

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

普通にバリデートして場合分けすればよいような気がしますが・・・

PHP

1<?PHP 2if(isset($_POST['hoge'])){ 3 $sql = "INSERT INTO hogeTable (hoge) VALUES(%s)"; 4 $hoge=filter_input(INPUT_POST,'hoge',FILTER_VALIDATE_INT,["options"=>["default"=>""]]); 5 $sql=sprintf($sql,$hoge===""?"NULL":"{$hoge}"); 6 print $sql; 7}else{ 8 print "postデータはありません"; 9}; 10?> 11<form method="post"> 12<input type="text" name="hoge" value=""> 13<input type="submit" value="go">:空データ 14</form> 15<form method="post"> 16<input type="text" name="hoge" value="-100"> 17<input type="submit" value="go">:マイナス 18</form> 19<form method="post"> 20<input type="text" name="hoge" value="0"> 21<input type="submit" value="go">:ゼロ 22</form> 23<form method="post"> 24<input type="text" name="hoge" value="012"> 25<input type="submit" value="go">:ゼロで始まる数字 26</form> 27<form method="post"> 28<input type="text" name="hoge" value="100"> 29<input type="submit" value="go">:普通の数値 30</form> 31<form method="post"> 32<input type="text" name="hoge" value="12.34"> 33<input type="submit" value="go">:小数点 34</form> 35<form method="post"> 36<input type="text" name="hoge" value="9,999"> 37<input type="submit" value="go">:カンマ区切り文字 38</form> 39<form method="post"> 40<input type="text" name="hoge" value="aaa"> 41<input type="submit" value="go">:文字列 42</form> 43<form method="post"> 44<input type="text" name="hoge" value="123xxx"> 45<input type="submit" value="go">:数字入り文字列 46</form> 47

投稿2016/10/05 00:43

編集2016/10/05 00:44
yambejp

総合スコア114572

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

MySQLでは、文字列を数値にキャストする際、数字から始まっていない文字列は全て 0 に変換されます。

sql

1mysql> SELECT CAST('' AS SIGNED), CAST('NULL' AS SIGNED), CAST('3hoge' AS SIGNED); 2+--------------------+------------------------+-------------------------+ 3| CAST('' AS SIGNED) | CAST('NULL' AS SIGNED) | CAST('3hoge' AS SIGNED) | 4+--------------------+------------------------+-------------------------+ 5| 0 | 0 | 3 | 6+--------------------+------------------------+-------------------------+ 71 row in set, 3 warnings (0.00 sec)

PHP の mysqli モジュールから MySQL に NULL を格納したい場合、
以下のようにバインド変数に(PHPの)NULL をセットしてください。

php

1// ユーザーからの入力がなかった場合にはNULLを代入 2if (count($_POST['hoge']) > 0) { 3 $value = (int) $_POST['hoge']; 4} else { 5 $value = null; 6} 7 8$stmt = mysqli_prepare($db, 'INSERT INTO hogeTable SET hoge = ?'); 9mysqli_stmt_bind_param($stmt, 'i', $value); 10 11mysqli_stmt_execute($stmt);

http://php.net/manual/ja/mysqli-stmt.bind-param.php

You can bind to variables with NULL values, and on update and insert queries, the corresponding field will be updated to NULL no matter what bind string type you associated it with.

投稿2016/10/04 23:46

KiyoshiMotoki

総合スコア4791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

php

1$sql = sprintf('INSERT INTO hogeTable SET hoge=IF("%s"="", NULL, "%s")', 2 mysqli_real_escape_string($db, $_POST['hoge']), 3 mysqli_real_escape_string($db, $_POST['hoge']) 4);

我ながら…なんとも場当たり的な対処。

投稿2016/10/04 15:06

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

そもそも論ですが、NULLってバッドプラクティスなのでは?
NULL撲滅委員会

数値の0ではダメで、NULLをわざわざ入れたい理由は何でしょう?

投稿2016/10/04 14:42

zico_teratail

総合スコア907

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DaiAoki

2016/10/04 14:55

NULLを格納したい理由は、hogeのAVGを取得して平均値を出す際に、未入力の項目はNULLとして除外したいからです。 0が格納されてしまいますと、平均値を正しく取得できないという問題があり、NULLを格納したいのです。
zico_teratail

2016/10/04 15:03

集計とかするなら、なおさらNULLは排除しといたほうが余計なバグが出ない気がしますが・・・。まあMySQLの場合はNULLを無視してAVG計算してくれるようですが。 でも「0」を使った場合でも0を除外して平均値を出す工夫はいくらでも出来そうですよ。 ↓ null - Mysql AVG to ignore zero - Stack Overflow http://stackoverflow.com/questions/5340883/mysql-avg-to-ignore-zero
guest

0

回答していただいた皆さん、ありがとうございました。
検討の結果、valueをNULLとし、SQL文のダブルクォーテーョンを外す方法が一番しっくりきたため、ベストアンサーに選ばせていただきました。
特にNULLの扱い方には注意が必要ということで、今後機能を増やしていった時に、今回の変更が悪影響を与えないように気をつけたいと思いました。

ありがとうございました。

投稿2016/10/05 12:45

DaiAoki

総合スコア67

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問