2012-01-18 6 views
6

DBIには、SELECTステートメントの実行されたステートメントハンドルがそれからフェッチせずに行を返すかどうかを判断する手段がありますか?

I.e.以下のようなもの:

use DBI; 
... 
my $sth = $dbh->prepare("SELECT ..."); 
$sth->execute; 

if (..$sth will return at least one row...) { 
    ... 
} else { 
    ... 
} 

と私は任意の$sth上のメソッドをフェッチ実行ずにテスト$sth will return at least one rowを実行したいです。

注 - 私は、行の正確な数(すなわち$sth->rows)を必要としない、私はちょうど$sth->rows>が0

答えて

8

$ sth->の行になりますかどうかを知る必要があり、まだあなたの最良の選択肢です。あなたが言ったように、それが0以上であるかどうかを確認してください。

if ($sth->rows > 0){ 
    # magic here! 
} 

EXCEPT! DBIドキュメントでは、すべての行がフェッチされるまで、選択されたステートメントではこれが信頼できないと述べています。前もってフェッチする行の数を決定する方法はありません。あなたがこれを知っておく必要がある場合のアドバイスは最初

select count(*) from <table> 

を行うことですthis section of the DBI documentationを参照してください。

+0

それはDBDと、たとえば、ドライバによっては動作しない場合があります::オラクル、$ sth-> rowsは、更新、削除、および挿入のためにのみ影響を受ける行の数を返しますが、selectの場合は-1を返します(http://search.cpan.org/~pythian/DBD-Oracle-1.74/lib/DBD/Oracle.pm# rows) – Fred

1

DBIで何かを探す代わりに、SQLを使用することができます。ただでSELECT別にSELECTラップして条件をEXISTS:

SELECT 1 FROM DUAL WHERE EXISTS (SELECT ...); 

それは、ポータブルSQLではありません:DUALから自分のRDBMSに異なって見えることがあり、あなたのDBはサポートしていない可能性が存在し、サブクエリ。しかし、現代のほとんどのDBでは、このようなものを作ることができます。

オプティマイザはサブクエリの制限をグループ単位で無視するので、最も効果的な方法です。実行計画を確認する。

SELECT COUNT(*) FROM (SELECT ...) 

でも可能ですが、DBは正しい数の行を取得するために全データセットをチェックする必要があります。

SQLビルダーを制御している場合は、by order by、group by(部分がない場合のみ)を削除し、その上にlimitを適用して1行だけを選択できます。

0

おそらく、これはあなたが探しているものです。

「アクティブ」

「アクティブ」属性は、ハンドルオブジェクトが「アクティブ」である場合はtrueです(boolean型、読み取り専用)。これはアプリケーションではめったに使用されません。アクティブの正確な意味は、現時点ではやや曖昧です。データベースハンドルの場合、通常 はハンドルがデータベースに接続されていることを意味します( "$ dbh-> disconnect"は "Active"をオフに設定します)。ステートメントハンドルの場合、通常、ハンドルはフェッチするデータがさらにある「SELECT」であることを意味します。 (すべてのデータを取得するか、 "$ sth-> finish"を呼び出すと "アクティブ"がオフに設定されます)

+0

いいえ、あなたの答えを引用するとき、 'Active'は通常、文ハンドル*が*フェッチする行をさらに持つかもしれないことを意味します。したがって、先験的な*がわかっている実行された文でさえも、最初の(そして最後の) 'fetch()'が呼び出されるまで 'DBD :: mysql'のような典型的なドライバの下で行が返されません。 – pilcrow

2

フェッチする以外の行をフェッチできるかどうかをテストする信頼できる方法はないと思います。もちろん、一度最初の行を取得したら、それをフェッチすることはできません。そして、その行を "手元に"保持する必要があります。しかしこれはあまりにも難しいことではありません。

私は一般的に次の二つのうちの一つのようなイディオムを使用するように思うだろう:

... 
$sth->execute; 

my @rows; 

my $row = $sth->fetchrow_hashref(); 

if ($row) { 
    do { 
     # do something with $row 
     ... 

     $row = $sth->fetchrow_hashref(); 
    } while ($row); 
} else { 
    # No rows 
} 

または

... 
$sth->execute; 

my @rows; 

while (my $row = $sth->fetchrow_hashref()) { push @rows, $row } 

if (@rows) { 
    # Some rows, now in @rows 
} else { 
    # No rows 
} 
+0

また、予想される結果が妥当なサイズである場合は、https://stackoverflow.com/a/47679059/111036に記載されているように '$ sth-> fetchall_arrayref()'を直接使用してください。 – mivk

関連する問題