perleager has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I'm trying to count the number of rows are in a MySQL table.

I have this following code that is producing no value.
my $dbhq = DBI->connect('DBI:mysql:TEST') or die "Couldn't connect to +database: " . DBI->errstr; $sqlq = "SELECT COUNT(*) As Total FROM TEST"; $sthq = $dbhq->prepare($sqlq) or die "preparing: ",$dbhq->errstr; $sthq->execute or die "executing: ", $dbhq->errstr; $rowq = $sthq->fetchrow_hashref; $total = $rowq->{'Total'}; $sthq->finish; $dbhq->disconnect; print "$total";


I have another script that has a similar code but the select statement has a WHERE Clause and it does give a value to the $total variable.

Anyone know why this would not work for me? I read this at the mysql site, and just wondering could this be the problmem? If it is, any way I can count the number of rows by using the DBI : rows function? http://www.mysql.com/doc/en/News-3.22.13.html

Thanks,

Anthony

Replies are listed 'Best First'.
Re: SELECT COUNT and DBI: rows
by gmax (Abbot) on Sep 28, 2003 at 20:56 UTC

    It works for me, if I add username and password to your connect statement.

    You say that your script produces no value. Does it mean that the $total variable is empty? It is not.

    It looks like what you posted is not the actual code you're using. Therefore, a few questions are necessary:

    Furthermore, the $sth->rows method doesn't return the number of rows in a table, but the number of rows affected by your statement, when your SQL contains modifying commands such as UPDATE, INSERT, DELETE.

    That method returns sometimes the number of records from a SELECT statement, but it is driver dependant, and not reliable, as you can see from the DBI docs. Using MySQL, it should return the number of rows if you execute a SELECT that fetches all the rows in your table, but a simple COUNT is less expensive.

    To count the number of rows, then, you need to use COUNT(*), as you did.

    Please read the above Tutorials, and then provide more information about your case.

    Update
    The error is NOT in the "AS" keyword as stated by ronzomckelvey. Such keyword is perfectly legal and functional in MySQL. (Updated again - OK, I see that both Zaxo and dws have pointed out that in detail.)

    _ _ _ _ (_|| | |(_|>< _|
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: SELECT COUNT and DBI: rows
by dws (Chancellor) on Sep 28, 2003 at 21:12 UTC
    Using mysql 3.23.56, I ran your script (after changing database names and passwords, and creating a TEST table), and it correctly displayed the number of rows in the table. However, because you're not printing a newline after $total, the count appeared merged with my shell prompt. I.e.,
    [dws@labrat test]$ perl total.pl 2[dws@labrat test]$ ^
    Is it possible you have some funky prompt that's obscuring the result? Try printing the result with a trailing newline.

    The link you provided indicates a problem with count(*) when doing an INNER JOIN, which your script doesn't.

Re: SELECT COUNT and DBI: rows
by Anonymous Monk on Sep 28, 2003 at 20:44 UTC
    You can't use the rows method on select statements, only on statements that modify the database. In those cases, for most DBDs $dbh->do($sql) returns the number of rows affected. In other words, you can't use rows to count the rows from a select statement. This is in perldoc DBI in some detail, under the ->rows method.
      You can't use the rows method on select statements, only on statements that modify the database.

      OK, now I'm really confused. I do that all the time! I do a select, and use rows to check if it returned anything. Don't I? (Goes to check...) yes I do. I have code like this:

      ## prepare some SELECT statement $sth->execute() || die "Error: " . $dbh->errstr; if( $sth->rows > 0 ){ ## do some stuff }


      ($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss') =~y~b-v~a-z~s; print
        OK, now I'm really confused. I do that all the time!

        It might work on whatever database you're using, but getting a row count back from a SELECT isn't portable.

      You can't use the rows method on select statements
      Where on earth do you see the rows() method used? I don't. My browser can't find it.

      I have no idea why it doesn't work for the OP. It seems to be working for me.

      Mea culpa: I don't know where I saw the rows method used either, but obviously that was some good **** I was smoking yesterday. Please ignore that post, and I'll go find more to share. :I
Re: SELECT COUNT and DBI: rows
by Cody Pendant (Prior) on Sep 29, 2003 at 02:10 UTC

    OK I'm really confused indeed right now.

    I've got working code which goes like this:

    $sth = $dbh->prepare( " SELECT ## long complicated WHERE stuff " ) || die "Error: " . $dbh->errstr; $sth->execute() || die "Error: " . $dbh->errstr; if( $sth->rows > 0 ){ ## print out some results }

    And according to this thread, I shouldn't do that, and I shouldn't rely on the results?

    What should I do instead? Should I do the whole thing twice, like this?

    $sth = $dbh->prepare( " SELECT COUNT(*) As Total ## long complicated WHERE stuff " ) || die "Error: " . $dbh->errstr; $sth->execute() || die "Error: " . $dbh->errstr; if( $Total > 0 ){ ## only if it passes this condition, do the REAL ## select and print out the results }

    That seems bizarrely innefficient.



    ($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss') =~y~b-v~a-z~s; print
      What should I do instead? Should I do the whole thing twice, like this? ... That seems bizarrely innefficient.

      I was deep into this issue several years back, and I wish I still had my old notes so that I tell you which of the then-major RDMBSs didn't provide a count at SELECT time. It had to do with how that particular RDMBS used lazy evaluation to produce its result set. (Lazy eval meant that no count was avaible until the result set was exhausted. I doubt that's what you want.) This might not be an issue with the current generation of significant databases. Perhaps others who work with the major vendors can chime in and let us know.

      If you've got something working with MySQL, a strategy of sticking with what you've got, but noting that there might be an issue should you port, may be good enough.

        Thanks for that. So DBI tells you not to rely on a rows count in general terms, but MySQL is a specific instance when you can? I'm happy with that. Mine's not the kind of code you port.


        ($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss') =~y~b-v~a-z~s; print
      If you want to do some function on your database, but only if there is something there to do it on, you could do the "two step" you suggested (COUNT (*) is very fast and fuly optimized in mySQL, so it does not "hurt" your database much), BUT your queries are not atomic and it could be that between your first step and the second step someone changed (deleted or added) the number of records so the result of your first test becomes invalid.

      Therefore, only do the second step and wrap the fetch-function in a while-loop. If you get no results out of your SELECT, the code inside the while-loop will not get executed and no harm is done.

      CountZero

      "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

A reply falls below the community's threshold of quality. You may see it by logging in.