こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

DBのWHERE~ANDの使い分けをphpで処理

<input type="text" name="aaaaa" value="">
<input type="text" name="bbbbb" value="">
<input type="text" name="ccccc" value="">
このinputは全部で30個あります。DBには30個のカラムがあって、
対象のカラムと比較する値valueが""のときはWHERE以降をやらないで、
1つ以上のときはWHERE句をやってANDで繋げて絞り込んでいきたいです。
$_GETのキー名とその対象のカラム名は別々につけています。
$_GETの値は文字列や数字が入ります。
<?php
mb_http_output('UTF-8');/*ajaxの読み込みにつかうファイルのため*/
mb_internal_encoding('UTF-8');/*ajaxの読み込みにつかうファイルのため*/

if(isset($aaaaa) && strlen($aaaaa)>0){
$aaaaa = mb_convert_encoding($_GET['aaaaa'], "UTF-8");
htmlentities($aaaaa, ENT_QUOTES);
$test1["id"] = $aaaaa;
}
if(isset($bbbbb) && strlen($bbbbb)>0){
$bbbbb = mb_convert_encoding($_GET['bbbbb'], "UTF-8");
htmlentities($bbbbb, ENT_QUOTES);
$test1["name"] = $bbbbb;
}
if(isset($ccccc) && strlen($ccccc)>0){
$ccccc = mb_convert_encoding($_GET['ccccc'], "UTF-8");
htmlentities($ccccc, ENT_QUOTES);
$test1["textdata"] = $ccccc;
}
/*あと27個つづきます*/

mysql_set_charset('utf8');
$my_1 = "SELECT * FROM tablename";
if(isset($test1) && !$test1==null){
foreach($test1 as $key => $value){$test2 = $key;}
$my_1 .= " WHERE ";
while($test1--){
$my_1 .= $test2."=".$test1[$test2]." AND ";
if($test1==0){$my_1 .= $test2."=".$test1[$test2];}
}
$my_1_q = mysql_query($my_1,$mysql);
}

/*$my_1を他のとこでも使いたい*/
$my_2 = $my_1." ORDER BY id LIMIT 0,10";
$my_2_q = mysql_query($my_2,$mysql);
$my_3 = "SELECT COUNT(*) AS ccc FROM tablename WHERE name='$aaaaa' AND bbbbb='$bbbbb'";
$my_3_q = mysql_query($my_3,$mysql);
if(!$my_1_q && !my_2_q && !$my_3_q){die(mysql_error());}

こんなかんじでやったのですが、クエリの作成でエラーになってしまいます。
できれば最初のifがいっぱい続くのももっと上手にできるようにしたいです。

投稿日時 - 2012-06-01 01:51:01

QNo.7507679

すぐに回答ほしいです

質問者が選んだベストアンサー

こんにちは。

何故エラーになるかのエラー内容を添付してもらえると回答が付き易いと思います。
また、SQLのエラーの場合はどういうSQLが生成されたかをprint等で画面に表示してみると修正のきっかけ見つかるかもしれません。

以下のような感じで実装できると思います。
入力内容のチェック等セキュリティについては省いていますのでその辺は実装して下さい。
またPOSTで書いています。ここは環境に合わせて下さい。

動作原理としてはパラメータ名とカラム名が違うのでそれを紐付ける連想配列を用意しています。
これによりformから送信されたパラメータ名がどのカラムであるか判断します。

あとは送られてきたパラメータとカラム名を紐付けながら条件を生成します。

ループ内での判断が面倒でしたので必ず" and カラム名='パラメータ値'"で条件を生成しておきます。
そのまま処理をすると
select * from TABLENAME where and id='value'
というSQLになってしまいますので
and以降をwhereにくっつけます。

<?php
// パラメータ名とカラム名を紐付けるマップ
$key = array (
'aaaaa' => 'id',
'bbbbb' => 'name',
'ccccc' => 'textdata',
'ddddd' => 'value1'
);

if ( isset($_POST) ) {
$sql = "select * from TABLENAME";
$where = "";
foreach ( $_POST as $k => $v ) {
// 送信内容をループ
if ( isset($key[$k]) && $_POST[$k] !== "" ) {
// 送信内容のキーがカラム名マップに存在し、
// 送信内容が入力されていたら条件に追加
$value = mb_convert_encoding ( $_POST[$k],"UTF-8" );
$where .= " and " . $key[$k] . "='" . $value . "'";
}
}
if ( strlen($where) > 0 ) {
// 条件が追加されている場合はSQLに追加する
// $whereの先頭には" and"が無条件に入っているためand以降をwhereに追加する
$where = " where " . substr($where,4);
$sql .= $where;
}
}
?>

投稿日時 - 2012-06-01 09:24:09

お礼

mb_convert_encodingとhtmlentitiesをまとめていっぺにできる方法があったので、それも使って直してみました。ちゃんと動くようになりました。ありがとうございます。

>if ( isset($key[$k]) && $_POST[$k] !== "" ) {
空白のチェックで != としないで !== するのは「0」への対策ですか?

<?php
mb_http_output('UTF-8');
mb_internal_encoding('UTF-8');

//--------------------------
//初めの値を設定
//--------------------------
$get['aaaaa'] = "";
$get['bbbbb'] = "";
$get['ccccc'] = "";
//30個分つづきます。
$get['zzzzz'] = 10; //表示数
$get['ppppp'] = 1; //ページの番号
//--------------------------

//$_GETは全部、中身がどうあれ処理させます
function abcdef($str) {
$str = mb_convert_encoding($str, "UTF-8", "UTF-8");
$str .= htmlentities($str, ENT_QUOTES, "UTF-8");
return $str;
}

if (isset($_GET)){
foreach($_GET as $key => $val){
$get[$key] = abcdef($val);
}
}

$key = array(
$get['aaaaa']=>'id',
$get['bbbbb']=>'name',
$get['ccccc']=>'textdata'
);

$my_1 = "SELECT * FROM infotable";
$where = '';
foreach($key as $k => $v){
if(isset($key[$k]) && $key[$k] !== ''){
$where .= " AND ".$key[$v]."='".$key[$k]."'";
}
}

if(strlen($where)>0){
$where = " where ".substr($where,4);
$my_1 .= $where;
}

$my_2 = $my_1." ORDER BY id LIMIT 0,10";
$my_3 = "SELECT COUNT(*) AS CNT FROM tablename WHERE id='".$get['aaaaa']."' AND name='".$get['bbbbb']."'";

mysql_set_charset('utf8');
$my_1_q = mysql_query($my_1,$mysql);
$my_2_q = mysql_query($my_2,$mysql);
$my_3_q = mysql_query($my_3,$mysql);

投稿日時 - 2012-06-02 02:48:07

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(3)

ANo.3

条件設定がない場合は「全て表示する」のか「一つも表示しない」のかで
処理がことなります。
今回のケースだと基本的に全て表示し、条件が提示されたとき
完全一致でAND絞り込みをしていくという流れにみえます
全て表示するのは「WHERE 1」としておくと便利です
絞り込みはあとANDでつないでいくだけです。

また、他のSQLで同じwhere条件を使うのであれば関数化するのが妥当です


<?PHP
$sql="SELECT * FROM hoge";
$sql.=setWhere();

function setWhere()
{
$str=" WHERE 1";
$list=array(
"aaaaa"=>"id"
,"bbbbb"=>"name"
,"ccccc"=>"textdata"
);
foreach($list as $key=>$val){
if(!isset($_REQUEST[$key]) or $_REQUEST[$key]==='') continue;
$str.=" AND `".$val."`='".mysql_real_escape_string($_REQUEST[$key])."'";
}
return $str;
}
print $sql;
?>
<form>
<input type="text" name="aaaaa" value=""><br>
<input type="text" name="bbbbb" value=""><br>
<input type="text" name="ccccc" value=""><br>
<input type="submit" value="go">
</form>

投稿日時 - 2012-06-01 11:39:26

お礼

mb_convert_encodingとhtmlentitiesをまとめていっぺにできる方法があったので、それも使って直してみました。ちゃんと動くようになりました。すごく参考になりました。

>WHERE 1
SELECT * FROM tablename;
SELECT * FROM tablename WHERE 1;
どっちが早いですか?

<?php
mb_http_output('UTF-8');
mb_internal_encoding('UTF-8');

//--------------------------
//初めの値を設定
//--------------------------
$get['aaaaa'] = "";
$get['bbbbb'] = "";
$get['ccccc'] = "";
//30個分つづきます。
$get['zzzzz'] = 10; //表示数
$get['ppppp'] = 1; //ページの番号
//--------------------------

//$_GETは全部、中身がどうあれ処理させます
function abcdef($str) {
$str = mb_convert_encoding($str, "UTF-8", "UTF-8");
$str .= htmlentities($str, ENT_QUOTES, "UTF-8");
return $str;
}

if (isset($_GET)){
foreach($_GET as $key => $val){
$get[$key] = abcdef($val);
}
}

$list = array(
$get['aaaaa']=>'id',
$get['bbbbb']=>'name',
$get['ccccc']=>'textdata'
);
$my_1 = "SELECT * FROM tablename";
$my_1 .= setWhere($list);

function setWhere($param){
$str = ' WHERE 1';
foreach($param as $key => $val){
if(!isset($key) or $key==='') continue;
$str .= " AND ".$val."='".$key."'";
}
return $str;
}

$my_2 = $my_1." ORDER BY id LIMIT 0,10";
$my_3 = "SELECT COUNT(*) AS CNT FROM tablename WHERE id='".$get['aaaaa']."' AND name='".$get['bbbbb']."'";

mysql_set_charset('utf8');
$my_1_q = mysql_query($my_1,$mysql);
$my_2_q = mysql_query($my_2,$mysql);
$my_3_q = mysql_query($my_3,$mysql);

投稿日時 - 2012-06-02 02:52:12

ANo.1

まず
if(isset($aaaaa) && strlen($aaaaa)>0){
 $aaaaa = mb_convert_encoding($_GET['aaaaa'], "UTF-8");
 htmlentities($aaaaa, ENT_QUOTES);
 $test1["id"] = $aaaaa;
}
の、1行目の$aaaaa は定義済みですか?
2行目に初めて$_GETからの代入があるように見受けられます。
それと、3行目の変換はスルーされています。

とりあえず、正確な書き方は偉人達にお任せして、大雑把にイメージですが、
function strConv( $strIn = "", &$strOut ) {
 if( strlen($strIn) ) {
  $strOut = $strIn;
  $strOut = mb_convert_encoding( $strOut, "UTF-8" );
  $strOut = htmlentities( $strOut, ENT_QUOTES );
  return 1;
 }
 return 0;
}
をどっかに置いて
if( isset( $_POST['aaaaa'] ) && strConv( $_POST['aaaaa'], $str ) ) $test1['id'] = $str;
if( isset( $_POST['bbbbb'] ) && strConv( $_POST['bbbbb'], $str ) ) $test1['name'] = $str;
などにすればすっきりはします。


次に、SQL作成部ですが、、、
foreach($test1 as $key => $value){$test2 = $key;}
とありますが、コピーミスなのか、オリジナルがこうなっているのか・・・。
$test2は値が1つだけしか入ってませんよ。

あと、while($test1--){...} はphpの文法にはないのではないでしょうか?


まずは、落ち着いて都度print_rなりechoなりで出力して状況を確かめてみるといいかと思われます。
また、phpはエラーが親切なので、それも記載されると的確な回答がしやすくなります。
ご参考になればいいのですが。

投稿日時 - 2012-06-01 08:36:41

お礼

いろいろ調べてみるとクエリの作成でなくて、ご指摘して頂いた通りphpの使い方が間違っていました。

>function strConv( $strIn = "", &$strOut ) {

strConv( $_POST['aaaaa'], $str )
function strConv( $strIn = "", &$strOut ) {

strConvの第一引数の意味は、$_POST['aaaaa']に値が入っていても""にするということですか?
あと&$strOutの&をつけるとreturnで返さなくても自動で返すようになるのですか?

投稿日時 - 2012-06-02 02:59:26

あなたにオススメの質問