SQLの効率化について

このQ&Aのポイント
  • SQLの効率化について質問があります。テーブルの特定のレコードとその子レコードを取得したいですが、現在は複数回のSQL実行が必要です。より効率的な方法があれば教えてください。
  • 以下のソースコードでは、テーブルから特定のレコード及びその子レコードを取得しています。しかし、複数回のSQL実行が必要であり、効率的ではありません。1回のSQL実行で同じ結果を得る方法を教えてください。
  • テーブルから特定のレコード及びその子レコードを取得する際、現在は複数回のSQL実行が必要です。より効率的な方法があれば教えていただきたいです。
回答を見る
  • ベストアンサー

SQLの効率化について

下記のようなテーブルがあり、idの値を渡すと、下記のレコードを取得したいと思います。 1. 渡されたid=idのレコード 2. 渡されたid=parent_idのレコード 3. 渡されたid=parent_idのid=parent_idのレコード 【テーブル】 CREATE TABLE IF NOT EXISTS `tbl` ( `id` varchar(4) NOT NULL, `name` varchar(100) NOT NULL, `parent_id` varchar(4) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `tbl` (`id`, `name`, `parent_id`) VALUES ('0001', '親1', '0'), ('0002', '親2', '0'), ('0011', '子1-1', '0001'), ('0012', '子1-2', '0001'), ('0021', '子2-1', '0002'), ('0022', '子2-2', '0002'), ('0101', '子1-1-1', '0011'), ('0102', '子1-1-2', '0011'), ('0103', '子1-1-3', '0011'), ('0121', '子2-1-1', '0021'); 下記はそのソースとなり、やりたい事は出来ているのですが、SQLを3回実行しています。 多分2回目の$idに1回目の結果の$row["id"]、3回目の$id[$cnt]に2回目の結果の$s_idをセットすることが出来れば、1回のsql文で記述できるのではと思いましたが、 どのようなSQL文を書けば良いか分からなかった為、アドバイスいただける方がいらっしゃいましたら、ご教示の程よろしくお願いします。 【ソース】 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja" dir="ltr"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>title</title> </head> <body> <?php $link = mysql_connect('MySQL サーバ','ユーザー名','パスワード'); if (!$link) { die('接続できませんでした:' . mysql_error()); } if (!mysql_select_db('データベース名', $link)) { die ('データベースの選択失敗'); } $hairetsu = array(); $f_id = array(); $f_name = array(); $f_parent_id = array(); $s_id = array(); $s_name = array(); $s_parent_id = array(); $t_id = array(); $t_name = array(); $t_parent_id = array(); // 1回目 $query = mysql_query("SELECT * FROM tbl where id = '0001'", $link); if (!$query) { die(mysql_error()); } $row = mysql_fetch_array($query); $hairetsu["f_id"] = $row["id"]; $hairetsu["f_name"] = $row["name"]; $hairetsu["f_parent_id"] = $row["parent_id"]; $id = $row["id"]; // 2回目 $query = mysql_query("SELECT * FROM tbl where parent_id = $id", $link); if (!$query) { die(mysql_error()); } while ($row = mysql_fetch_array($query)) { array_push($s_id, $row["id"]); array_push($s_name, $row["name"]); array_push($s_parent_id, $row["parent_id"]); } $hairetsu["s_id"] = $s_id; $hairetsu["s_name"] = $s_name; $hairetsu["s_parent_id"] = $s_parent_id; $id = $hairetsu["s_id"]; // 3回目 for($cnt=0; $cnt<count($id); $cnt++) { $query = mysql_query("SELECT * FROM tbl where parent_id = $id[$cnt]", $link); if (!$query) { die(mysql_error()); } while ($row = mysql_fetch_array($query)) { array_push($t_id, $row["id"]); array_push($t_name, $row["name"]); array_push($t_parent_id, $row["parent_id"]); } } $hairetsu["t_id"] = $t_id; $hairetsu["t_name"] = $t_name; $hairetsu["t_parent_id"] = $t_parent_id; echo "<pre>"; var_dump($hairetsu); echo "</pre>"; mysql_close($link); ?> </body> </html> 以上、宜しくお願いします。

  • MySQL
  • 回答数2
  • ありがとう数2

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

  • ベストアンサー
  • xKENx
  • ベストアンサー率65% (21/32)
回答No.1

SQLの発行回数を減らすということであれば下記のようなSQLで1度に結果取得できると思います。 iroha_168さんのサンプルプログラムをSQLで表現した感じです。 SELECT * FROM tbl WHERE id = '0001' OR parent_id = '0001' OR parent_id IN (SELECT id FROM tbl WHERE parent_id = '0001')

iroha_168
質問者

お礼

ご回答ありがとうございます。 ご教示いただいたSQL文で意図した動作となりました。 このたびはどうもありがとうございました。 以上、よろしくお願いします。

その他の回答 (1)

  • nora1962
  • ベストアンサー率60% (431/717)
回答No.2

こんな感じでしょうか? select `id`, `name`, `parent_id` from `tbl` where `id` = '0001' or `parent_id` = '0001' union all select `id`, `name`, `parent_id` from `tbl` where `parent_id` in ( select `id` from `tbl` where `parent_id` = '0001' ); 最近のOracleやPostgreSQL、SQL Serverでは with t as ( select id, name, parent_id from tbl where parent_id = '0001' ) select id, name, parent_id from tbl where id = '0001' union all select id, name, parent_id from t union all select id, name, parent_id from tbl where parent_id in ( select id from t ) とも書けますが。

iroha_168
質問者

お礼

ご回答ありがとうございます。 ご教示いただいた1つ目のSQL文で意図した動作となりました。 また、OracleやPostgreSQL、SQL Serverでの記述方法もご教示いただきありがとうございます。 それらのデータベースを使用する際は参考にさせていただきたいと思います。 このたびはどうもありがとうございました。 以上、よろしくお願いします。

関連するQ&A

  • SQLのどこがおかしいでしょうか?

    PHP4、MySQLです。 for($i=1;$i<34;$i++){ $sql = "select count(group) as cnt".$i." "; $sql.= "from stock "; $sql.= "where group=".$i." "; //print "sql= ".$sql."<br>"; $result = mysql_query($sql,$db) or die("失敗しました".mysql_error ()); $Row = mysql_fetch_array($result, MYSQL_ASSOC); $cnt.$i = $Row['cnt".$i."']; } としています。どこがおかしいでしょうか? 教えてください。 よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • mysql_fetch_objectの書き方を教えて下さい。

    PHP5.1.6を使用しています。 次のスクリプトを書きましたが、データが取得できません。 $conn_id = mysql_connect("localhost","***","***") or die('Error connecting to MySQL'); mysql_select_db('***',$conn_id); $query ="SELECT abcd,efgh from XYZ where name='taro'"; $result = mysql_query($query,$conn_id) or die($query.'failed('.mysql_error().')'); $ydata = array(); $xdata = array(); while($row = mysql_fetch_array($result)){  ← 11行目 array_push($ydata, $row->efgh);   ← 12行目 array_push($xdata, $row->abcd);   ← 13行目 } エラーログを見ると、 PHP Notice: Trying to get property of non-object in /***/***/****.php on line 12 PHP Notice: Trying to get property of non-object in /***/***/****.php on line 13 となっています。 var_dump($row) 句を入れ、ブラウザから見ると、当然ながら(?)bool(false) と表示されます。 11行目の mysql_fetch_array を mysql_fetch_object に入れ換えて while($row = mysql_fetch_object($result)){ としても結果は変わりません。 リファレンスマニュアルやサンプルを参照して種々手直ししましたが、今ひとつ正解に辿り着けません。 データを取得して配列に入れるには、どのように修正すれば良いか、教えて頂けませんでしょうか。

    • ベストアンサー
    • PHP
  • PHPでjavascriptの2次元配列を宣言する

    はじめまして。 とっても困ってるので質問させてください。 「データベースからの取り出したデータをjavascriptで扱いたい」 下記のソースでjavascriptの2次元配列を宣言しているつもりなのですが、 データの取り出しが上手くいきません。。。 宣言自体ができてないのでしょうか??? PHPのソースを貼り付けます↓ echo "<script type=\"text/javascript\">"; echo "//<![CDATA["; echo "var SKind_name=new Array(".$temp.");"; for ($i=1;$i<=$cat_dtcnt;$i++) { $sql_scat_cnt = "SELECT COUNT(*) AS cnt FROM `map_subkind` WHERE kind_id = '".$i."'"; $res_scat_cnt = mysql_query($sql_scat_cnt) or die("データ抽出エラー"); $row_scat_cnt = mysql_fetch_array($res_scat_cnt, MYSQL_ASSOC); $scat_dtcnt = $row_scat_cnt["cnt"]; $temp = $scat_dtcnt+1; echo "SKind_name[".$i."]=new Array(".$temp.");"; echo "SKind_name[".$i."][0]=".$scat_dtcnt.";"; $sql_subcat= "SELECT * FROM `map_subkind` WHERE kind_id = '".$i."'"; $rst_subcat=mysql_query($sql_subcat) or die("データ抽出エラー"); $scatcnt = 1; while($row_scat=mysql_fetch_array($rst_subcat)) { echo "SKind_name[".$i."][".$scatcnt."] = \"".mb_convert_encoding($row_scat["skind_name"],"SJIS","EUC-JP")."\";"; $SKind_name_array[$i][$scatcnt] = mb_convert_encoding($row_scat["skind_name"],"SJIS","EUC-JP"); $scatcnt ++; } $scatcnt--; } echo "// --></script>";

  • SQLによって計算した変数を次のSQLに代入できますか?

    user(テーブル) id | name | bango 1 | taro | 1001 2 | sato | 1012 3 | miho | 1027 4 | hiro | 1066 *idはautoincrement、bangoはユニークの値 mark(テーブル) id | check | bango 1 | 0 | 1001 2 | 1 | 1001 3 | 1 | 1001 4 | 0 | 1012 5 | 0 | 1012 6 | 1 | 1027 7 | 1 | 1027 8 | 0 | 1066 *idはautoincrement、checkは1か0、bangoはユニークの値 checkが1の確立が高い順にnameを一覧表示したいのですが、 うまく2つのテーブルを繋げることができません。 queryによって計算した変数を次のqueryに代入することはできるのでしょうか? 具体的には以下のような感じです。 bangoが1001のcheck=1の確立を出す場合 //bangoが1001の数 $test1 = mysql_query("select count(id) from mark where bango='1001';",$conn $row1 = mysql_fetch_array($test1, MYSQL_ASSOC); $totalct1 = $row1["count(id)"]; //bangoが1001かつcheckが1の数 $test2 = mysql_query("select count(id) from mark where bango='1001' and check='1' ;",$conn) $row2 = mysql_fetch_array($test2, MYSQL_ASSOC); $totalct2 = $row2["count(id)"]; //bangoが1001かつcheckが1の確立 if($totalct2==0){ $kakuritu = '0' ; } else{ $kakuritu = $totalct2 / $totalct1 * 100 ; } 上記の変数を下記のように入れ込むことはできないのでしょうか? $test3 = mysql_query("select name from user order by $kakuritu ;",$conn)

    • ベストアンサー
    • MySQL
  • mysql_fetch_objectにデータを取得させたいのですが、うまく行きません。

    データ型 name varchar(30), item1 char(8), item2 int(6) で、テーブルが下記のようなっています。 | name |item1 | item2 | | taro | abcd | 53 | | taro | efghk | 48 | | taro | lmnp | 02 | while文で array_push($ydata, $row->item1) として $row = mysql_fetch_object($result) にデータを取得させたいのですが(スクリプト下記)、 $conn_id = mysql_connect("localhost","***","***") or die('Error connecting to MySQL'); mysql_select_db('***',$conn_id); $query ="SELECT item1,item2 from XYZ where name='taro'"; $result = mysql_query($query,$conn_id) or die($query.'failed('.mysql_error().')'); $ydata = array(); while($row = mysql_fetch_object($result)){   ←10行目 // array_push($ydata, $row->item1);      //  ここに下記の13、14行目を追記 } var_dump($row);echo"<br />\n"; var_dump($result); print_r($row); echo"<br />\n"; これでブラウザから見ると bool(false) resource(3) of type (mysql result) としか出ません。(19行目の結果は表示されません。) そのため 13: echo "item1",$row['item1'],"<br>"; 14 echo "item2",$row['item2'],"<br>"; と追記してブラウザから見ると、単に [ item1 ]とだけ表示されます。 10 行目を while($row = mysql_fetch_arrayt($result)){ に変えてブラウザから見ると item1abcd item253 imem1efghk item250 item1lmnp item258 bool(false) resource(3) of type (mysql result)   となります。 $row = mysql_fetch_object($result) にデータを取得させるにはどのように修正すれば良いのでしょうか?

    • ベストアンサー
    • PHP
  • テーブルのデータをarray (array (***, ***)) の形式で取得したい

    id、氏名、年月日(date)、点数(tensu)の列を持つテーブルseiseki があります。 <?php $conn_id = mysql_connect("localhost","root","*****") or die('Error connecting to MySQL'); mysql_select_db('******',$conn_id); $query ="SELECT date,tensu from seiseki; $result = mysql_query($query,$conn_id) or die($query.'failed('.mysql_error().')'); $date = array(); $tensu = array(); while($row = mysql_fetch_array($result)){ $date[] = $row['date']; $tensu = $row['tensu']; } print_r($date); echo "<br/>\n";      ←15行目 print_r($tensu); echo "<br/>\n";      ←16行目 ?> これをブラウザで見ると、 Array ( [0] => 2009-05-01 [1] => 2009-06-07 [2] => 2009-07-24 ・・・・・・ ) Array ( [0] => 80 [1] => 75 [2] => 90 ・・・・・・・ ) となります。 15,16行目をコメントアウトして print_r($row[“date”],[“$tensu”]); とするとエラーになります。 array (array (2009-05-01, 80), array (2009-06-07, 75 ), array (2009-07-24 , 90)・・・・・・・ ); の形式でデータを取得するにはどのようにすれば良いでしょうか?

    • ベストアンサー
    • MySQL
  • mysql sqlエラー

    先ほども質問したのですが再度質問させていただきます mysql limitページ分割を行っていてエラーは消せたのですが今度 SQLエラーになり出来ません 前の人が質問したのを参考にしてつくったのですがうまくいかず困っています 検索結果を10件ずつ表示して googleみたいに 1l 2l 3 みたいな感じやりたいです <body> <?php error_reporting(E_ALL ^ E_NOTICE); //データベースに接続 if (!$con = mysql_connect("localhost", "root", "admin")) { echo "接続エラー" ; exit ; } //データベースを選択 if (!mysql_select_db("db_test", $con)) { echo "データベース選択エラー" ; exit ; } //LIMITを使ったSELECT文を作成 $sql = "select * from tbl_test where (氏名 LIKE '%{$_GET['name']}%') or (住所 LIKE '%{$_GET['name']}%')"; $sql = "limit" . $page * 10 . ", 10" ; //SQL実行 if (!$res = mysql_query($sql)) { echo "SQLエラー<BR>" ; exit ; } //検索結果表示 echo "<table border=1>" ; echo "<tr> <th>番号</th> <th>氏名</th> <th>住所</th> <th>操作</th> </tr>" ; while($row = mysql_fetch_array($res)){ $ID = htmlspecialchars($row['番号']); $NAME = htmlspecialchars($row['氏名']); $ADDR = htmlspecialchars($row['住所']); echo "<tr> <td>$ID</td> <td>$NAME</td> <td>$ADDR</td> <td><a href='edit.php?番号=$ID'>修正</a> <a href='delete.php?番号=$ID'>削除</a></td> </tr>"; //検索条件に該当する全データの件数取得 $sql = "select count(*) from tbl_test " ; $sql = "where (氏名 LIKE '%{$_POST['name']}%') or (住所 LIKE '%{$_POST['name']}%')"; if (!$res = mysql_query($sql)) { echo "SQLエラー<BR>" ; exit ; } $row = mysql_fetch_array($res) ; $cnt = $row[0] ; //ページ表示 if(!$cnt > 10) echo ceil($cnt / 10), "ページの中の", $page + 1, "ページ目を表示<br>" ; //前の10件 if ($page_num != 0) { echo "<a href = find.php?name=".$name. ". $page -1.>" ; echo "&lt 前の10件"; } //次の10件 if (($page_num + 1)*10 < $cnt) { echo "<a href = find.php?name=".$name. ". $page +1.>" ; echo " 次の10件 &g</a>t" ; } //結果セットの開放 mysql_free_result ($res) ; //データベースから切断 mysql_close($con) ; } ?> </body> </html>

    • ベストアンサー
    • MySQL
  • mysqlからphpに表示ですべての項目を出したい

    phpとmysqlの勉強をしているのですが、出したい項目がでてきてくれません。 今mysqlでidとnameとpriceの項目を作っているのですが、以下だとどうしてもnameしか出てきてくれません。 どうすれば3つの項目がでてくれますでしょうか? よろしくお願いします。 <?     mysql_connect('localhost' , 'root' , '') or die(mysql_error());     mysql_select_db('db1'); mysql_query('SET NAMES UTF8'); $sql="SELECT * FROM syouhin"; $res=mysql_query($sql); $options=""; while($row = mysql_fetch_array($res,MYSQL_ASSOC)){ $options.="<input type=\"radio\" name=\"syouhin1\" value='{$row['id']}' checked>        {$row['name']}\n<br>"; } $select="{$options}</select>\n";     print $select; ?>

    • ベストアンサー
    • PHP
  • phpでmysqlからの呼び出しについての質問です。

    phpでmysqlからの呼び出しについての質問です。 現在mysqlから下記のように値を呼び出し、age=10の条件にあてはまるものだけを3つまで表示させたいと思っています。 $query = "SELECT id, name, birth, age FROM log WHERE age=10 LIMIT 0 , 3"; $hoge = $db->rowset_assoc($query) or $db->error("Query failed $query".__FILE__.__LINE__); foreach($hoge as $row) { $id= $row['id']; $name= $row['name']; $birth= $row['birth']; } $hoge = array( array("$id","$name","$birth"), array("$id","$name","$birth"), array("$id","$name","$birth"), ); 更新の度にシャッフルさせたいのでarrayを使用しているのですが、 これだと3つとも同じ数値が出てきてしまい困っています。 それぞれの値を取り出し、arrayに入れるにはどのようにすれば良いのでしょうか。 宜しくお願い致します。 大文字小文字の使い方については参考資料そのままに作成しましたので おかしい部分があるかもしれません。

    • ベストアンサー
    • PHP
  • 重複が

    新規登録の時の重複をチェックしたいです テーブルのカラムはシンプルにidとnameとpassだけです nameに同じ名前の人がいると困るので、HTMLフォームから送られた名前と登録してある名前の重複がないかチェックするようにできますか? やってみましたが動きません(ーー;; $name = mysql_real_escape_string($_POST['name']); $name3=array(); $name2 = mysql_query('SELECT name FROM hoge2 WHERE name=$name'); while($data = mysql_fetch_assoc($name2)) { array_push($name3, $data['name']); } if(isset($name3)){ print "重複があります"; }else{ //ここからsql $sql = sprintf('INSERT INTO hoge2 SET name="%s", pass="%s"', $name, mysql_real_escape_string($_POST['pass']) ); //ここまで mysql_query($sql) or die(mysql_error()); }

    • ベストアンサー
    • MySQL