何か、ここの質問掲示板は自己レスが出来ないシステムらしいので(自己解決は放置推奨?)、同じような問題で躓く方のためにここに質問内容と解決方法を記述しておきます。
■環境
サーバ:Apache
言語 :Perl
DB :MySql
■質問内容
データベースから取得したデータを配列に格納することができません。
唯一、以下の方法で格納できたのですが、この場合データベースの項目の数が、あらかじめ分かっている場合にしか使用できません。googleで検索して出てくるサンプルは全てループ内でprintしているので参考になりませんでした。
やりたいことは単純で、データベースにクエリーを発行した結果の複数レコードをそのまま配列に格納することです。perlに詳しい方がおられましたらよろしくお願いします。
■解決方法
#以下の一行を
@result[$i] = ([$work[0],$work[1],$work[2],]);
#以下に変更
push @result, [@work];
※但し、実行速度などのパフォーマンスまでは実験していません。取得するレコード数が多くなった場合のパフォーマンスの低下など考慮が必要なことがあるかもしれませんし、もっと効率的なやり方があるかもしれません。もしより完成度の高い解決方法をご存知の方がおられましたら、後学のためにも回答をお願いいたします。
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
■データベース内のデータ
id=1,subid=1,data1=aaa
id=1,subid=2,data1=bbb
id=1,subid=3,data1=ccc
■期待する結果(一部修正)
@result = (["1","1","aaa"],
["1","2","bbb"],
["1","3","ccc"],
)
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
■実際のソース
**********************************************************
use DBI;
#//■DB接続
$db = DBI->connect("DBI:mysql:$DbName:$DbHost", $DbUser, $DbPass);
$sth = $db->prepare($sql);
$sth->execute;
$cnt = $sth->rows;
for($i=0; $i<$cnt; $i++){
@work = $sth->fetchrow_array;
#以下の一行を
#@result[$i] = ([$work[0],$work[1],$work[2],]);
#以下に変更
push @result, [@work];
}
#//■CLOSE
$sth->finish;
$db->disconnect;
for($i=0; $i<$cnt; $i++){
print "<p>".$result[$i][0]."/".$result[$i][1]."/".$result[$i][2]."</p>\n";
}
**********************************************************
■表示
1/1/aaa
1/2/bbb
1/3/ccc
No.3ベストアンサー
- 回答日時:
こんにちは、
>*******************************************
>◆[2]リファレンスを代入した場合
>for($i=0; $i<$sth->rows; $i++){
>@work = $sth->fetchrow_array;
>$result[$i] = \@work;
>}
>※0.002~0.004秒(10件)0.4~0.5秒(50件)
>*******************************************
これの @result には期待した結果が得られなかったんじゃないですか?
@result の各要素に格納されたのは全部同じ @work へのリファレンスになる気がします
my @work = $sth->fetchrow_array;
でレキシカル宣言すれば、それぞれ違う @work へのリファレンスになり期待した結果になると思います。
(検証してませんので違ったらすみません。)
>もともと[3]のやり方は随所で「メモリーを大量に消費するので非推奨」
>*******************************************
>◆[3]一度に全部のデータを取得した場合
>$ref = $sth->fetchall_arrayref;
>@result = @$ref;
>※0.002~0.004秒(10件)0.5~0.6秒(50件)
>*******************************************
確かにこれはそうだと思い、(一応)とつけて書きました。
ですが、どの方法でも最終的に全てのデータを @result に格納するつもりなら、
結局メモリは使っちゃいますよね。
なら、
>@result = @$ref;
こういった形でコピーせずに、取得したリファレンスを直接使えば、
fetchall_arrayref でも良いと思いますけど。
データの数を制限するなら、
SQLを書くときにそうなるように書くか(その方法は知りません)
my @recs = ();
while ( my $rec_ref = $sth->fetchrow_arrayref ){
push @recs , $rec_ref;
last if scalar @recs > 100;
}
みたいにするかですかね
>配列に格納すること自体をあまりしないのかもしれないですね。
まあ、表示するだけなら、配列にバッファしたりしないで、
一つずつ処理した方が良いのかも知れませんが、
そうもいかない場合もあるでしょうね、
まあ、大きいデータだと分かっているなら、
不用意にコピーせずに、リファレンスをうまく使うのが良いかもですね。
まあ、私は一般人(謙遜じゃありません)なので、参考程度で。
また前後してしまいました。
[2]はご指摘の通りmyが抜けてますね。ソースにはコメントで記述があるのでこちらへ書き込むときに消えたのだと思います。
[3]は、@$refのコピーを生成しているからその分単純に時間が掛かっているのですね。プログラムの構造上、取得したデータ全体の配列、若しくはデータの配列への参照が必要だったのですが、$sth->fetchrow_arrayrefで取得した$refの参照をreturnしてあげた方がパフォーマンス的によさそうですね。実際はSQLを発行する際にソートと絞り込みは行うのでそんなに膨大なデータにはならないと思います。
大分助かりました、ありがとうございました。
No.2
- 回答日時:
こんにちは、
>完成度の高い解決方法
かどうかは?かも知れませんが。
なにしろ TMTOWTDI(There's more than one way to do it.)
なのでいろいろですね、
速さについてはベンチマーク取ったりしないと分かりません。
ループで配列にフェッチなら、
my @recs = ();
while ( my @rec = $sth->fetchrow_array ){
push @recs , \@rec;
}
もしくは配列のリファレンス
my @recs = ();
while ( my $rec_ref = $sth->fetchrow_arrayref ){
push @recs , $rec_ref;
}
一応、一度に全部ってのもありますね。
my $array_ref = $sth->fetchall_arrayref;
で、最初のヤツですけど、
>@result[$i] = ([$work[0],$work[1],$work[2],]);
これは理解しにくいですね。
配列のスライスへ、無名配列へのリファレンスを一つリストとして代入ですかね?
分かっていてやっているならかまいませんけど。
@work をmyでレキシカル宣言しといて、
$result[$i] に @work へのリファレンスを代入すれば、
御希望の処理になったかも知れません。
for($i=0; $i<$cnt; $i++){
my @work = $sth->fetchrow_array;
$result[$i] = \@work;
}
で、push にして、$i が必要なくなったなら、
while ( my @work = $sth->fetchrow_array ){
push @result, \@work;
}
の方が私は見やすいですね。
参考までに。
参考URL:http://search.cpan.org/~timb/DBI-1.58/DBI.pm
この回答への補足
回答ありがとうございます。
早速教えていただいたいくつかの方法で実験してみました。ネットワーク上のサーバでの実験なので、そのときの回線速度に影響されやすいですが、複数回数実験した平均値で計測してみました。(異常に高い数値は除外)取得データ10件の場合のページリクエストしてから表示されるまでの時間と50件の場合です。
*******************************************
◆[1]pushで配列に格納した場合
for($i=0; $i<$sth->rows; $i++){
@work = $sth->fetchrow_array;
push @result, [@work];
}
※0.002~0.004秒(10件)0.4~0.5秒(50件)
*******************************************
*******************************************
◆[2]リファレンスを代入した場合
for($i=0; $i<$sth->rows; $i++){
@work = $sth->fetchrow_array;
$result[$i] = \@work;
}
※0.002~0.004秒(10件)0.4~0.5秒(50件)
*******************************************
*******************************************
◆[3]一度に全部のデータを取得した場合
$ref = $sth->fetchall_arrayref;
@result = @$ref;
※0.002~0.004秒(10件)0.5~0.6秒(50件)
*******************************************
実験の結果、[1]と[2]は殆ど差が出ませんでしたので、好みの問題かもしれません。ただ共通して言えることは、データ件数は5倍程度なのに、掛かった時間が100~200倍となっているので、大規模データを配列で運用するのは限界があるのかなと思います。
次に[3]の結果ですが、10件程度だと[1][2]との差はありませんが、50件になると250倍~300倍となってしまい、もともと[3]のやり方は随所で「メモリーを大量に消費するので非推奨」との記事が散見されたので実験はしていませんでしたが、実行速度の面においても厳しいのかなと思いました。
ちなみにperlだと一般的にどのやり方が主流なのでしょうか?もしかすると配列に格納すること自体をあまりしないのかもしれないですね。
自分の記事を訂正できないようなのでこちらで失礼します。
実験で時間が掛かりすぎると思って調べたところブラウザの表示に時間を取られているようでした。再計測したら以下の通りでした。これだとどれを使っても許容範囲のような気もしますね。
___10件____50件
[1]0.002~3____0.003~4
[2]0.002~3____0.003~5
[3]0.002~4____0.004~7
No.1
- 回答日時:
記述したところで質問でない物は削除されますので無意味かつネット資源の無駄遣いという事で有害ですらあります。
日記ならチラシの裏にでもどうぞ。
この回答への補足
****************************
※但し、実行速度などのパフォーマンスまでは実験していません。取得するレコード数が多くなった場合のパフォーマンスの低下など考慮が必要なことがあるかもしれませんし、もっと効率的なやり方があるかもしれません。もしより完成度の高い解決方法をご存知の方がおられましたら、後学のためにも回答をお願いいたします。
****************************
これが質問なのですが。読めませんか?
だから質問の緊急度もちゃんと変えてあるでしょう。
逆に伺いたいのですが、貴殿の書き込みによって誰か得をする方でもおられますか?ネット資源の無駄遣いと言うのなら同じような質問が大量に出回って放置されている方がよりそうなのだと私は思いますけどね。特に技術系の質問は質問内容と結果が結びついて初めてネット資源として有効なのだと思いますが。
少なくとも貴殿のこの書き込みを見て喜ぶのは貴殿自身だけで、全く他を益さないということだけは理解した方が今後の貴殿自身のためだと思います。
まぁ、貴殿のような人物が私の目の前で堂々と同じことが言えるとはとても思えませんが、顔が見えないということで好き勝手ができる。ネットの弊害ですね。
ストレス発散のための書き込みならチラシの裏にでもどうぞ。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- CGI perlで書いたcgiでsqliteの使い方を教えてください 2 2023/05/08 21:29
- PHP PHP一覧表示した項目にリンクをはりたい 1 2023/07/12 17:08
- Visual Basic(VBA) Selenium.ChromeDriverの使い方について 7 2022/09/22 06:43
- その他(プログラミング・Web制作) python OpenPyXLを使って出力結果をエクセルに書き込み 2 2022/06/04 19:46
- フリーソフト 色々な形式の個人情報を後で参照しやすいようWindow10で管理したいのですが、どんな方法があるの? 1 2023/04/29 16:46
- Visual Basic(VBA) access count数を変数に格納 2 2022/03/30 19:21
- その他(データベース) pythonでsqlight勉強中、クエリー結果の利用法教えて下さい 1 2022/04/28 20:38
- PHP PHP MySql ページング 2 2022/09/20 06:38
- オープンソース Python openpyxlを使用したセル番地の使用について 1 2023/08/03 22:05
- Ruby pandasでsqlite3にテーブル作成・追加・読み出しでindexの取り扱い方教えてください 5 2023/03/08 09:57
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
データベースから取得したデー...
-
正規表現 perl 連続ヒットの...
-
配列に入った変数を二度使いたい
-
アルファベットn文字の組み合わ...
-
画面を強制的に再描画させる方法
-
VBのReturnの使い方
-
ハッシュ検索はなぜ速い
-
乱数の桁数指定、または範囲指定。
-
VBA横データを縦にしたいです
-
VBA for i=1 to lastrow
-
UWSCの終了の仕方
-
エクセルVBAでTransposeの不思議
-
ExcelVBAで、index、match関数...
-
短いハッシュの作り方
-
VB.NETで素因数分解のプログラ...
-
マクロ Publicでの配列定義
-
ループを回すという意味は何で...
-
二次元配列のインデックスについて
-
ループフリー
-
文字列を変数名として扱う方法
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
データベースから取得したデー...
-
perlで2つの配列を比較する方...
-
DBIを使ってのデータの取り出し...
-
python質問
-
perlでファイルの拡張子を除い...
-
grep関数を用いた複数行からの抽出
-
アルファベットn文字の組み合わ...
-
半角文字の縦書き表示
-
乱数と順列と組み合わせ
-
配列やハッシュで中身が同じか...
-
桁数指定と四捨五入
-
ループ中でのmy宣言と処理速度
-
画面を強制的に再描画させる方法
-
VBAで3秒だけ時間を止めたい
-
VBAでの一時停止と再開の方法
-
VBのReturnの使い方
-
どなたかこのプログラミングを...
-
Escキーを押すと、中断する時と...
-
UWSCの終了の仕方
-
エクセルの当番表を作っていま...
おすすめ情報