web-dev-qa-db-ja.com

2つの別々の処理呼び出しを実行せずに、DBIで行数を取得するにはどうすればよいですか?

PerlでDBIを実行していますが、プリペアドステートメントを実行したときに、返される行数が0であるかどうかを確認する方法がわかりません。

行をフェッチするwhileループ内にカウンターを設定できることに気付きましたが、それを行うための醜い方法がないことを望んでいました。

12
Genia S.

結果セットに含まれる行数を確認するには、次の2つのオプションがあります。

  1. select count(*)
  2. 結果セットを反復処理し、行をカウントします。

配列またはもっと凝ったものを返すストアドプロシージャを介して魔法を導入することができますが、最終的にはこれら2つのことのいずれかが発生する必要があります。

したがって、その結果を得るための派手な方法はありません。あなたはそれらを数える必要があります:-)

9

クイックルックに基づくと ここ 、実行した後のようです

$statement->execute($arg)

次の方法で行数にアクセスできます

$statement->rows
19
Harper Shelby

ドキュメントの「警告」 (別の回答のコメントにリンクされています)は重要であり、実際の正しい回答を提供します。

一般に、行数に依存できるのは、non-SELECTの実行後(UPDATEやDELETEなどの特定の操作の場合)、またはすべてのSELECTステートメントの行。

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

11
John Siracusa

少し遅れていますが、誰かがOracleを使用している場合は、ここに汗の解決策があります。

SELECT
  q.*,
  ROWNUM DB_ROWNUM,
  (SELECT max(ROWNUM) FROM ($sql)) DB_COUNT
FROM
  ($sql) q

もちろん、$ sqlはクエリです。 Oraclesオプティマイザは、すべてを2回実行しないほどインテリジェントです。

これで、フェッチされたすべての行がDB_ROWNUMに現在の行番号(ページンググリッドの行番号付けに役立ちます)とDB_COUNTに行の完全な数を保持します。少なくとも1つの行をフェッチする必要があります(したがって、上記の質問に対する正確な答えではありません;))が、次に汗を使用します。

これは、Oracleで開始と制限を実行し、それでも完全な行数を取得するための非常に簡単な方法でもあります。

SELECT * FROM (
  SELECT /*+ FIRST_ROWS($limit) */
    q.*,
    ROWNUM DB_ROWNUM,
    (SELECT max(ROWNUM) FROM ($sql)) DB_COUNT
  FROM
    ($sql) q
  WHERE
    ROWNUM <= $limit
)
WHERE
  DB_ROWNUM > $start

これにより、グリッドの2番目のページの行51から100のみを実際にフェッチできますが、フェッチされたすべての行に実際の行番号(1から開始)と完全なカウント(開始と制限なし)があります。

4
Neo van Goth

このSQLソリューションを試して、データのSQLをcountステートメントと組み合わせてください。

 tablexからnull、null、null、count(*)を選択
 union 
 tablexからfoo、bar、foobar、nullを選択

最初のステートメントにはカウントがあり、最初の行である必要があります(そうでない場合は、それを回避するために注文できます)。その後、残りのレコードセットを自由に循環できます。

2
Ward Kaatz

CPANは言う:

[...]またはSELECTステートメントのすべての行をフェッチした後。

したがって、このようなことを行うとおそらくうまくいくでしょう:

$sth->execute() or die $sth->errstr();
my $hasref = $sth->fetchall_hashref('id');
say "There is/are " .  scalar(keys(%{$hasref}) . " row(s).";
2
Weeble

SQLを動的に生成して実行しました。私にとっては、クエリを再生成する必要があるため、select count(*)はオプションではないようです。次のアプローチは私にはきれいに見えました。ただし、行データを取得するには、もう一度s $h->execute()を発行する必要があります。

$h->execute() or die "ERROR: Couldn't execute SQL statement";
$rowcount_ref = $h->fetchall_arrayref(0);
$rowcount = scalar (@{$rowcount_ref});

--Shaakunthala

1
Shaakunthala

他の人がすでに言ったように、あなたは本当に行があるかどうかを見つけるために行を取得する必要があります。すべての行でループを開始する前に知る必要があり、期待される結果が大きくない場合は、すべての結果を配列に入れて、それを確認できます。

私は最近そのようなものを使用しました:

foreach my $table ( qw(ACTOR DIRECTOR PRODUCER WRITER) ) {
    my $sth = $dbi->prepare(qq{SELECT * FROM $table WHERE DESCRIPTION != TRIM(DESCRIPTION)})
        or die $dbi->errstr;
    $sth->execute or die $sth->errstr;

    my @rows = @{ $sth->fetchall_arrayref() };

    next unless @rows;

    foreach my $row (@rows) {
        print join(", ", map {qq("$_")} @{$row}), "\n";
    }
}
0
mivk

代わりに、データベースにカウントを実行させます。行数だけが必要な場合。 2018年1月のすべての行を検索します。

$year='2018';
my $qry = "SELECT COUNT(`my_key`) FROM `mtable` WHERE `my_date` LIKE '$year-01-%';";
my ($count) = $dbc->selectrow_array($qry);
0
agrov8

行は、データベース/ドライバーのバージョンによって間違いなく異なります。私は間違いなく、予期しない結果を処理するロジックの一部に目を向けます。

0
hpavc

すべての行をウォークスルーする前に行がいくつあるかを知りたい場合、MySQL固有のソリューションは FOUND_ROWS() である可能性があります。

最初のクエリで、SELECTの直後に_SQL_CALC_FOUND_ROWS_を追加します。次に、SELECT FOUND_ROWS();を実行すると、行数にすぐにアクセスできます。これで、すべての行をウォークスルーするか、それを実行するための最良の方法を決定できます。

クエリにLIMITを含めると、LIMITなしでクエリが返した合計数が得られることに注意してください。

0
Richlv