20

基本的に、Perl を使用してデータベースを検索し、特定の ID を持つアイテムがあるかどうかを確認しようとしています。この検索で​​は行が返されないこともありますが、行が返されることもあります。

次のコードがあります。

my $th = $dbh->prepare(qq{SELECT bi_exim_id FROM bounce_info WHERE bi_exim_id = '$exid'});
$th->execute();
if ($th->fetch()->[0] != $exid) {
        ...

基本的に、これは ID が返されたかどうかを確認し、返されていない場合はスクリプトを続行します。しかし、それは Null 配列参照エラーをスローしています$th->fetch()->[0]。行が返されたかどうかを確認するにはどうすればよいですか?

4

7 に答える 7

38

DBD::mysqlドライバーには、rows()結果のカウントを返すメソッドがあります。

$sth = $dbh->prepare( ... );
$sth->execute;
$rows = $sth->rows;

これはデータベース ドライバー固有であるため、他のドライバーでは機能しないか、他のドライバーでは異なる方法で機能する可能性があります。

于 2009-01-13T21:44:42.260 に答える
13
my $th = $dbh->prepare(qq{SELECT bi_exim_id FROM bounce_info WHERE bi_exim_id = '$exid'});
$th->execute();
my $found = 0;
while ($th->fetch()) 
{
   $found = 1;
}

行が存在しない場合、クエリは何も返さないため、フェッチを逆参照することはできません。

更新:次のように書き直すことをお勧めします

my $found = $th->fetch();
于 2009-01-13T21:12:49.533 に答える
5

「select count(*) ...」だけにしてみませんか??

my ($got_id) = $dbh->selectrow_array("SELECT count(*) from FROM bounce_info WHERE bi_exim_id = '$exid'");

または、 Little Bobby Tablesを阻止するには:

my $q_exid = $dbh->quote($exid);
my ($got_id) = $dbh->selectrow_array("SELECT count(*) from FROM bounce_info WHERE bi_exim_id = $q_exid");

または、これを何度も実行する場合:

my $sth = $dbh->prepare("SELECT count(*) from FROM bounce_info WHERE bi_exim_id = ?");
....save $sth (or use prepare_cached()) and then later
my ($got_id) = $dbh->selectrow_array($sth, undef, $exid);
于 2009-01-13T23:45:48.507 に答える
4

select を変更して、常に何かを返すようにしますか? これはSybaseで機能するはずですが、他のDBについては知りません。

my $th = $dbh->prepare(qq{SELECT count(*) FROM bounce_info WHERE bi_exim_id = '$exid'});
$th->execute();
if ($th->fetch()->[0]) {
....
}
于 2009-01-13T21:24:26.203 に答える
2

一般的に、人々が例外をそれほど恐れる理由がよくわかりません。あなたはそれらを捕まえて先に進みます。

my $sth = prepare ...
$sth->execute;
my $result = eval { $sth->fetchrow_arrayref->[1] };

if($result){ say "OH HAI. YOU HAVE A RESULT." }
else       { say "0 row(s) returned."         }

ただし、この場合、ポールの答えが最適です。

また、$sth->rowsすべての行をフェッチするまで、通常は機能しません。一致する行数を知りたい場合は、答えを知りたい質問を実際にデータベース エンジンに尋ねなければなりません。つまりselect count(1) from foo where bar='baz'

于 2009-01-13T21:59:21.467 に答える
1

SELECT クエリによって返される行数を確認する唯一の確実な方法は、それらをすべてフェッチしてカウントすることです。DBIのドキュメントに記載されているように:

一般に、SELECT 以外の実行後 (UPDATE や DELETE などの特定の操作の場合)、または SELECT ステートメントのすべての行をフェッチした後にのみ、行数を信頼できます。

SELECT ステートメントの場合、通常、すべての行をフェッチしない限り、返される行数を知ることはできません。アプリケーションがこれまでにフェッチした行数を返すドライバーもあれば、すべての行がフェッチされるまで -1 を返すドライバーもあります。したがって、rows メソッドまたは $DBI::rows を SELECT ステートメントで使用することはお勧めしません。

ただし、実際にやってみると、事前に知る必要はほとんどありません。ループしwhile ($sth->fetch)て各行を処理するか、0 行または 1 行のみを返すクエリの特殊なケースでは、

if ($sth->fetch) {
  # do stuff for one row returned
} else {
  # do stuff for no rows returned
}
于 2009-01-13T22:37:10.487 に答える
1

この記事は、バージョン 8 より前の MySQL のユーザーを対象としています。

http://www.arraystudio.com/as-workshop/mysql-get-total-number-of-rows-when-using-limit.html

幸いなことに、MySQL 4.0.0 以降では、クエリで SQL_CALC_FOUND_ROWS オプションを使用できます。これにより、MySQL は LIMIT 句を無視して合計行数をカウントするようになります。行数を取得するために 2 つ目のクエリを実行する必要がありますが、これは単純なクエリであり、データを取得したクエリほど複雑ではありません。

使い方はとても簡単です。メインクエリでは、SELECT の直後に SQL_CALC_FOUND_ROWS オプションを追加する必要があり、2 番目のクエリでは FOUND_ROWS() 関数を使用して行の総数を取得する必要があります。クエリは次のようになります。

SELECT SQL_CALC_FOUND_ROWS name, email FROM users WHERE name LIKE 'a%' LIMIT 10;

SELECT FOUND_ROWS();

唯一の制限は、SQL_CALC_FOUND_ROWS は行数をどこにも保存しないため、最初のクエリの直後に 2 番目のクエリを呼び出す必要があることです。

このソリューションにも 2 つのクエリが必要ですが、メイン クエリを 1 回だけ実行するため、はるかに高速です。

SQL_CALC_FOUND_ROWS および FOUND_ROWS() の詳細については、MySQL のドキュメントを参照してください。

悲しいことに、8.0.17 の時点で:

SQL_CALC_FOUND_ROWS クエリ修飾子とそれに付随する FOUND_ROWS() 関数は、MySQL 8.0.17 で廃止されました ...

詳細はこちら

于 2012-11-07T10:33:04.643 に答える