• ベストアンサー

PHPのSQL文のデバッグ方法とコーディング方法について

http://okwave.jp/qa3663217.html 上記のANo.2の回答についての疑問です 本来上記の回答者に対して便乗質問すればよかったのですが、 早々に締め切られてしまったので新しく質問させていただきます。 ☆上記のANo.2でSQLのデバッグ方法が回答されいる(下記に抜粋)のですが、 (1)は一般的なSQLデバッグ方法なのでしょうか? (2)は一般的なSQLの記述方法なのでしょうか? ●ANo.2の抜粋 (1)SQL文はヒアドキュメントをつかう (2)テーブルやフィールドはバッククォート、値はシングルクォートでくくる (3)変数は{$hoge}形式で参照する (4)SQL文の最後になるべく;はつけない (5)エラーはmysql_error()で確認する。 ●抜粋終わり ○私が疑問に思う理由は下記のとおりです。 (1)はHTML文を出力するには有効な機能だと思います しかし、SQLをデバッグする場合(特に動的SQLをデバッグする場合)、 最終的に加工されたSQL文をvar_dump,echo,print等で一切加工せずにデバッグしないと、 ヒアドキュメントへ加工中にSQLが(タイプミスとかカットアンドペーストミス)変わってしまう可能性があり、正しくデバッグできない可能性があると思います。 特にデバッグする人は、SQLをヒアドキュメントへ転記中に無意識のうちに正常なSQLに変換してしまっていて、バグの原因が掴めないなんてケースは結構見てきました。 デバッグする人は何がバグっているのかを探っているはずので、出来るだけデバッグ対象コードはまず生のまま見るべきだと思っています。 また、デバッグ終了後にデバッグ文を消す作業が発生し、 誤ってデバッグコード以外の必要なコードも削除してしまう恐れもあります。 var_dumpであれば、一括置換でコメントアウトしたり出来ますし、 あるいは、var_dumpをラップする関数を用意しておき、 デバッグフラグがONの場合のみvar_dumpを走らせるようにしておけば、 var_dumpを削除する作業そのものが不要で、 必要な時にデバッグON/OFF出来るかと思います。 (2)は「値はシングルクォート」(※1)は納得できるのですが、 「テーブルやフィールドはバッククォート」(※2)は、※1と混在してSQLを書いた場合、どれが列名でどれが変数(または定数)なのか、判別しにくくなり、 余計なバグを混入させたり、可読性を落としたりすると思います。

noname#246547
noname#246547
  • PHP
  • 回答数4
  • ありがとう数5

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

  • ベストアンサー
  • inu2
  • ベストアンサー率33% (1229/3720)
回答No.2

あくまでも個人的な意見 1. ヒアドキュメントでSQL文の生成はしない。PHPのヒアドキュメントって処理遅いんで考えたことすらないですね。 $sql = "SELECT column1,column2 FROM table_name WHERE id = :id AND user_name = :user_name "; 等のように作りこんでおいて、プリペアドステートメントを使ってクエリーしております。 (*個人的に、SQLの予約語や関数、構文は大文字で、テーブル名、カラムは小文字で という法則で作るのが好きなだけです) 2. >「テーブルやフィールドはバッククォート」(※2)は、※1と混在してSQLを書いた場合、どれが列名でどれが変数(または定数)なのか、判別しにくくなり、、・・・ 私はプリペアドステートメントを使いますので、混乱する要素が皆無となりますので判別しにくいということはありえなくなります。 また、カラム名を ` で囲むことで SQLの予約語なのか カラム名なのかを判別しやすくなると思います。 といっても、` で囲むのってMySQLだけですので 一般的にはSQLの予約語をカラム名に使うなんてこと有り得ないので、DB設計時に予約語をカラム名にしてしまうヤツがどうかしているという事 3. ちなみに、 $sql = "SELECT column1, column2 FROM table_name WHERE id='{$id}' AND user_name='{$user_name}'"; とやるよりも $sql = "SELECT column1, column2 FROM table_name WHERE id='".$id."' AND user_name='".$user_name." "; のほうが速度的には速いです。 個人的には、プリペア主義なのでこういう悩みはありません。 4. プリペア主義なので・・・以下略 5. throwするのは設計者の自由なので、なに使ってもいいんじゃないでしょーかね?

noname#246547
質問者

お礼

返答ありがとうございます >$sql = "SELECT column1,column2 FROM table_name WHERE id = :id AND user_name = :user_name "; >等のように作りこんでおいて、プリペアドステートメントを使ってクエリーしております。 この書き方はOracleのProC*を使用していたころに書いたことがあります。 いままでのSQLの書き方では一番可読性がよいと思いました。 ただ、ProC*のプリペアドステートメントでは、WHERE句をifやfor等で可変条件に出来なかったため、使い勝手が悪かったですね。 PHPだと、文字列変数内に記述できるため使いやすそうです。 >` で囲むのってMySQLだけですので なるほど、MySQLの方言だったのですね。 当方MySQLはほとんど触ったことが無かったので知りませんでした。 方言であるならば、やはり他のDBにならって"` "を使用しないほうが、 保守性が良い感じがしますね。 ソースコードは一度作成したらシステムが運用終了するまで、 保守する必要があるが、保守する人間が必ずしもMySQLに精通しているとは限らないので、他のDBでも一般的なコーディングスタイルのほうが保守性が良い気がします。 >DB設計時に予約語をカラム名にしてしまうヤツがどうかしているという事 同意です。 これを許すと不要なバグを増やすだけだと思います。 これを許さなければ、「カラム名を ` で囲むこと」は不要な気がします。

その他の回答 (3)

  • wp_
  • ベストアンサー率54% (132/242)
回答No.4

>私がつかう理由は手が抜けて、バグが減るから。 確かに初期作成時は楽でよいのですが、それをそのままにされると運用・改修時に見づらくなるのですよ。 昨今のエディタではコード部とデータ部の色分けが可能なので、ヒアドキュメントでずらーっと書かれると逆に鬱陶しくなります。^^; もっとも、一番大きな理由としてはやはり「パース後に内部変換を行うので処理が非常に重い」ということですけどね。No.2の方も言及されてますけど。 「見づらい」に関連しますが、私的に大きな要因としてインデントが崩れるということがあります。 特にSQLの場合、桁を上げたら上げっぱなしで終わる(明示的な終了がない)のでどこからどこまでがクエリが比較的分かりづらくなります。 ヒアドキュメント内でも同じだけインデントすればいいじゃんと言った新人が居ましたが、彼には一時間正座してもらいました。^^; やはりクエリはクエリで単体テストを行い、正しいクエリであることが保証された上でコードに組み込むのがベストかと思います。 ともあれ、「現在作成時の作業簡素化」か、「処理の最適化・後続の人間のための可読性」かを取るならやはり後者が一般的ではないかなぁと。 >SQL 当方は新人のころOracleメインだった影響で全部大文字にするのが好きですね。 たまにSelectとかFromとか見て発狂しそうになります。 当然、書いた奴は正座ですが。

noname#246547
質問者

お礼

返答ありがとうございます。 >確かに初期作成時は楽でよいのですが、それをそのままにされると運用・改修時に見づらくなるのですよ。 同意です。 大半のプログラマは現在の仕様を満たすだけでその後のことを考えずにコードを書くことが多い気がします。 運用後の保守や、再利用のことを考えてコーディングする人ってまずお目にかかったことがありません。納期に追われてそれどころじゃないんでしょうけど。 あと、コーディングは若い人が担当することが多いので、 そもそも、運用・改修のことなんて気が付きもしない感じですね。 >特にSQLの場合、桁を上げたら上げっぱなしで終わる(明示的な終了がない)のでどこからどこまでがクエリが比較的分かりづらくなります。 最後に明示的な終わりもありますし、これはヒアドキュメントを使ったほうが有利な気がしますね。 >ともあれ、「現在作成時の作業簡素化」か、「処理の最適化・後続の人間のための可読性」かを取るならやはり後者が一般的ではないかなぁと 同意です。 趣味でプログラムして他の人間がコードを読むことがない場合なら前者ですが、仕事等で不特定多数が読む可能性がある場合は後者であると思います。 >当方は新人のころOracleメインだった影響で全部大文字にするのが好きですね。 >たまにSelectとかFromとか見て発狂しそうになります。 同意です(笑) 当方もOracle上がりなので予約語は大文字が基本ですね。 これをするだけでかなり可読性が上がりますね。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.3

元文書を書いた身としては一応、意見をだしておきます。 #1さんのいう「クエリは変数化しておけ」が、メインですね。 変数化の手段としてのヒアドキュメントということで。 ま、一言でいえば「いやならつかわなければいいんじゃない?」 ってことで・・・ (1)意外にヒアドキュメントは結構嫌われているのですね。 いろんなやり方を模索してきましたが私的にはヒアドキュメントが もっともしっくりくる作業効率化の手段になっています。 私がつかう理由は手が抜けて、バグが減るから。具体的には・・・ ・無駄にクォーテーションのエスケープでパースする必要がない ・変数をたしこんでいくやり方だと、区切り文字を入れ忘れるバグなどがある ・コマンドや条件を行単位でつけられきる ・SQLのエラーが行番号をかえしてくれる場合があり、エラー箇所を確定しやすい ・行単位の処理なのでSQLのコメントアウトがつかえる(#処理) ・なによりもSQLがSQL文として表示されるので直観的でデバッグしやすい 特に動的なSQLになるほど、ヒアドキュメントのありがたみがでてきます $条件1="AND ・・・・"; $条件2="AND ・・・・"; $条件3="AND ・・・・"; $sql=<<<eof SELECT * FROM hoge WHERE 1 {$条件1} {$条件2} {$条件3} eof; こんな風に書きますね。 (2)バッククォートは一般的です。 このQ&Aでも何度もバッククォートさえつければ、引っかからなかった バグの質問があがっています。 テストテーブルつくってついつい直観的な予約語をフィールド名に つかってしまうなど、ままあるでしょう。 もちろん使わない方が見やすくて、バグをださない自信があるなら 無理につけなくても構いませんが、保険でつけておいても損はありません。 たしかに他のSQLへの乗り換えの際には確かに変更が面倒かもしれませんね。

noname#246547
質問者

補足

返答ありがとうございます。 質問の性質上、本来はアンケートカテゴリがふさわしいかと思いましたが、 yambejp様の意見をぜひ伺いたいと思いまして、 目に触れる可能性の有るこのカテゴリで投稿させていただきました。 yambejp様の回答を勝手に転用してしまい不快な思いをさせてしまったとおもいます。この点深くお詫び申し上げます。 それでは本題に入らせていただきます。 >ま、一言でいえば「いやならつかわなければいいんじゃない?」 たしかにそうなのですが、コレを言い出すとQ&Aの意味が無いので スルーさせていただきます。 >(1)意外にヒアドキュメントは結構嫌われているのですね。 嫌われているかどうかは解りませんが、私はこの方法でSQLを埋め込んでいるソースを見たことがありませんでした。 簡単なツールや一時的な確認用のソースなど、将来にわたって保守する必要がないプログラムには使い勝手が良いと思いました。 >・無駄にクォーテーションのエスケープでパースする必要がない たしかにこれは有効ですね >・変数をたしこんでいくやり方だと、区切り文字を入れ忘れるバグなどがある これはヒアドキュメントならば入れ忘れることが少ないとはいいがたい気がします。 >・コマンドや条件を行単位でつけられる これはヒアドキュメントにアドバンテージがあるとは思えません。 条件によって検索条件が変動する場合、ifやforなどの制御文で条件を変える必要があるはずなので、この部分はヒアドキュメントの外で作らざる得ないのでは? >・SQLのエラーが行番号をかえしてくれる場合があり、エラー箇所を確定しやすい これは優れていますね >・行単位の処理なのでSQLのコメントアウトがつかえる(#処理) プログラム内部から発行するSQL文なので、代入文ごとプログラムが提供する1行コメントアウトで消しても問題ないと思うのですが。 唯一SQL文内にSQLのコメントが必要だったプログラムは、 Oracleでルールベースオプティマイザの制御をSQLのヒントとして与える必要があった場合でした。 >・なによりもSQLがSQL文として表示されるので直観的でデバッグしやすい ですが、 >$条件1="AND ・・・・"; 中略 >eof; を見る限り 動的な部分はヒアドキュメント以外の方法で処理されており、 「SQL文がSQL文として表示される」のは不変的な部分のみで、 ヒアドキュメント以外の方法と大差ないような気がします。 >テストテーブルつくってついつい直観的な予約語をフィールド名に つかってしまうなど、ままあるでしょう。 すいませんが、私はありませんでした。 理由はNo.2のお礼の最後の部分に記載してあります。 最後に、貴重な時間を割いて返答していただき誠にありがとうございました

  • wp_
  • ベストアンサー率54% (132/242)
回答No.1

>(1)は一般的なSQLデバッグ方法なのでしょうか? おそらくヒアドキュメント云々、ではなく「クエリは変数化しておけ」と言うことを言いたかったのではないかと邪推しますが。 ちなみに当方はヒアドキュメントは使わせません。HTMLだろうがSQLだろうが使った奴は殴ります。 // というかSQLとPHPは別個で単体テストすべきでは。 >(2)は一般的なSQLの記述方法なのでしょうか? これに関しては一般的といわざるを得ません。 >余計なバグを混入させたり、可読性を落としたりすると思います。 というのは完全に記述者の腕です。読み取れない方or読みづらく記述した方が悪いです。

noname#246547
質問者

お礼

返答ありがとうございます。 >完全に記述者の腕です。読み取れない方or読みづらく記述した方が悪いです。 埋め込みSQLを可読性、保守性、品質すべてを保つようにコーディングするのは難しいですよね。 SQLが複雑になればなるほど、今後保守する人にいかに見やすいコードにするか悩むところですよね。 しばしば、SQLの整合性を考えるより、いかに見やすくするかに時間をかけることのほうが多い場合もありました。

関連するQ&A

  • リレーションをSQL文で作る方法は?

    urizakaです 今まではSQL-Serverを使っていたのですが、今度からPostgresSQLを使うこと になりました。 さて、そこで質問なのですが、SQL文でテーブルを作るとき、他のテーブルの カラム(フィールド)と作ったテーブルのカラム(フィールド)のリレーションを 作るにはどうすれば良いのでしょうか? 特に、シリアル型で作ったフィールドの値を外部参照キーとして持ってきたい 場合はどのようにSQL文を書けばよいのでしょうか? すみませんが、よろしくお願いします。

  • SQL文ニ関して

    下記の3つのテーブルから下記フィールドを結合するSQL文を教えてください。 条件 ※SQL*PLUSを使用 ※店舗コードと営業日は共通(フィールドCDは別名) ※掛金額・商品券金額・クレジット金額はそれぞれフィールド数が10個(種類別) ※掛金額・商品券金額・クレジット金額はそれぞれ10個のフィールドを合計し  その合計したフィールドのみを表示させる。別名をつける。 ※必要な店舗コードのみを抽出する。  ※エディタにSPOOLする。 テーブル(1) フィールド名 1 店舗コード 2 営業日 3~12 掛金額 13~22 商品券金額 23~32 クレジット金額 テーブル(2) フィールド名 1 店舗コード 2 営業日 3 現金売上金額 テーブル(3) フィールド名 1 店舗コード 2 営業日 3 現金過不足 宜しくお願いします。

  • SQL文の書き方

    SQLを勉強しています。 レコードの中で指定フィールドの文字列が、指定文字から始まるレコードを取り出したいのですがSQL文の書き方がわかりません。 例) 1, AAA 2, BBB 3, CCC 4, ABC 上記の4つのレコードから"A"から始まるレコードを取り出したい。 結果は[1, AAA]と[4, ABC]が欲しいのです。

  • SQL文で

    T-SQLを使用しています。 下記のような場合どのようにSQL文を組めばよいのでしょうか?Group byを使用すると思うのですが・・・ テーブル名:SampleTbl フィールド1:ID(プライマリ) フィールド2:Name(varchar(4)) 【名前】 フィールド3:UpTime(varchar(16))【更新時刻】 ※UpTimeの概要 yyyyMMddhhmmssss 2004/06/01 12:00:0000 中身 1,鈴木,2004060112000000 2,鈴木,2004060112050000 3,鈴木,2004060112100000 4,鈴木,2004060112200000 5,山田,2004060112000000 抽出条件: 同一の名前で更新日が5分以内の範囲で更新されているデータのみ抽出する 抽出結果 1,鈴木,2004060112000000 2,鈴木,2004060112050000 3,鈴木,2004060112100000 上記の抽出結果を取得するにはどのようにすればよいか、ご教授お願い致します。

  • SQL文の質問

    SQL文で質問です。 コード 状態 1 0 1 1 2 0 3 1 のようにあった場合、 コード毎にみて、状態1があるコードは 結果に出さないようにしたいのです。 期待する結果は、 コード 状態 2 0 です。 どのようなSELECT文にしたらできますか? よろしくお願いします。

  • SQL文でフィールド名に空白を含んでいるとき

    CSVファイル検索の際のSQL文のことですが、フィールド名に半角空白を含んでいるものがあります。この場合の書き方についてアドバイスいただけないでしょうか。 例  where 科目 = keyword 上記の科目に 「未 払 金」のように空白を含んだものがある。 #Replaceは違うようで・・。レコードに空白があるのならわかりますが・・。 #上記SQL文は簡単にしてあり、そのままの書き方ではありません。

  • PHP+PDO+MYSQL で実行されたSQL文の取得について

    PHP+PDO+MYSQL で実行されたSQL文の取得について PEARのDBからPDOへの移行をしていましてデバック用のSQL文取得で困っています。 $sql = "SELECT * FROM sample where id = ? And id2 = ?" PEARのDBでは $db->query($sql,array(1,5)); $db->last_query; で実行したSQL文を取得することは可能でした。 PDOの場合 $sql_result = $pdo->prepare($sql); $sql_result->execute(array(1,5)); でリプレースフォルダ(クォート処理?)を利用してSQLを実行出来るようですが、 実行したSQLを確認する方法がマニュアル等を読みましたがどうしても分かりません。 どなたかご存知の方がいらっしゃいましたらご教授お願い致します。

    • ベストアンサー
    • PHP
  • PHPのSQLインジェクションはsprintf?

    PHPのSQLインジェクションですが、sprintf内でクォートをしてあるとそれで大丈夫なのでしょうか? 以下のようなコードがあり、nameは画面入力なのでSQLインジェクションが起こるのでは? と作成者に確認したところ、"%s"してあるから大丈夫との返事をもらいました。 ネット調べるとmysql_real_escape_stringでエスケープしてから"%s"で変換すれば大丈夫といった内容は見つけたのですが、mysql_real_escape_stringなど不要との返事をもらいました。 なぜ?と聞くとそういうものだとしか回答がありません。 sprintf('UPDATE users SET name = "%s" WHERE id = %d', name, id); 結局上記のコードでSQLインジェクションは解消されているのでしょうか?

    • ベストアンサー
    • PHP
  • VBAでSQL文の実行の記述について

    こんにちは。アクセスVBA初心者です。 どなたか教えてください! キーが二つあるテーブルに対して、 クエリやマクロを使わずにSQL文を使って存在チェック処理を行って、 ・0件ならば、画面入力値で登録処理、 ・0件でないならば、画面入力値で担当者名を更新処理 という処理を行いたいのですが、 どのようにVBA上でSQL文を記述し、 上記の条件を記述すればいいのかわかりません。 ちなみにテーブル名は「担当者マスタ」で フィールドは ・「支店コード」→第一キー ・「担当者コード」→第二キー ・「担当者名」 です。支店と担当者の組み合わせはユニークです。 画面フォーム名は「担当者マスタメンテ」で 画面フィールドは ・「支店コード」コンボボックス ・「担当者コード」コンボボックス ・「担当者名」テキストフィールド です。 どうか教えてください!お願いいたします!

  • php上でSQL文を実行した結果と、phpMyAdminで実行した結果が違う

    ☆実行環境 php5.3 MySQL4.0 $sql="SELECT * FROM テーブル名 WHERE フィールド名 like '".$変数."%'" php上で上記のようなSQL文を実行させようとしています。 テーブルには該当する行がいくつかあるのですが、ページ上では1行も表示してくれません。 mysql_num_rowsの返り値を見ると0になっています。 SQL文の組み立てがおかしいのかと思い、phpMyAdmin上でSQL文を実行すると、 きちんと欲しい内容が表示されます。 とするとphpでのSQL文の書き方がおかしいのだと思います。 どこかおかしいのかご教授ください。

    • ベストアンサー
    • PHP

専門家に質問してみよう