views:

2800

answers:

6

I am running following PHP code to interact with a MS Access database.

$odbc_con = new COM("ADODB.Connection");
$constr = "DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=" . $db_path . ";";
$odbc_con -> open($constr);

$rs_select = $odbc_con -> execute ("SELECT * FROM Main");

Using ($rs_select -> RecordCount) gives -1 though the query is returning non-zero records.

(a) What can be the reason? (b) Is there any way out?

I have also tried using count($rs_select -> GetRows()). This satisfies the need but looks inefficient as it will involve copying of all the records into an array first.

A: 

Doesn't Access have its own COUNT operator? eg:

$rs_select = $odbc_con -> execute ("SELECT COUNT(*) FROM Main");
Oli
This is not desired as it will lead to multiple SQL queries - one to get count and another to get records.The objective is to retrieve record-set and check it's record count to validate it.
VarunGupta
The only other options I can see (that you have already, too) involve unnecessarily shipping a lot of data around to count it. Triggering an extra little query seems a lot more reasonable.
Oli
+1  A: 

It is possible that ODBC doesn't know the recordcount yet. In that case it is possible to go to the last record and only then will recordcount reflect the true number of records. This will probably also not be very efficient since it will load all records from the query.

As Oli said, using SELECT COUNT(*) will give you the result. I think that using 2 queries would still be more efficient than using my first method.

Otherside
+1  A: 

Basically, Access is not going to show you the whole record set until it needs to (it's faster that way for much of the user experience anyway) - especially with larger recordsets.

To get an accurate count, you must traverse the entire record set. In VBA I normally do that with a duo of foo.MoveLast and foo.MoveFirst - I don't know what the php equivalents are. It's expensive, but since it sounds like you are going to be processing the whole record set anyway, I guess it is OK.

(a side note, this same traversal is also necessary if you are manipulating bookmarks in VBA, as you can get some wild results if you clone a recordset and don't traverse it before you copy the bookmark back to the form's recordset)

CodeSlave
That actually depends on the data interface you are using. DAO recordsets return a recordcount of 1 or more if records are returned, and 0 if none are returned, but the recordcount cannot be trusted to be accurate until you've issued a .MoveLast command. ADO and ODBC are different.
David-W-Fenton
+1  A: 

ADODB has its own rules for what recordcount is returned depending on the type of recordset you've defined. See:

MS Knowledge Base article 194973

W3C Schools article

In the example above, the PHP COM() object is used to instantiate ADODB, a COM interface for generic database access. According to the PHP documentation, the object reference produced is overloaded, so you can just use the same properties/methods that the native ADODB object would have. This means that you need to use the ADODB methods to set the recordset type to one that will give an accurate recordcount (if you must have it). The alternative, as others have mentioned, is to use a second query to get the COUNT() of the records returned by the SELECT statement. This is easier, but may be inappropriate in the particular environment.

I'm not an ADO guru, so can't provide you with the exact commands for setting your recordset type, but from the articles cited above, it is clear that you need a static or keyset cursor. It appears to me that the proper method of setting the CursorType is to use a parameter in the command that opens the recordset. This W3C Schools article on the CursorType property gives the appropriate arguments for that command.

Hopefully, this information will help the original poster accomplish his task, one way or the other.

--
David W. Fenton
David Fenton Associates

David-W-Fenton
A: 

If you're using a dynamic cursor type of connection, then it could actually change. Someone may delete a record from that database while you're browsing through pages of records. To avoid, use a static sort of snapshot cursor. I have this bookmarked which will explain it well. This always got me and the bookmark always reminded me why.

http://support.microsoft.com/kb/194973

Optimal Solutions
...but Jet does not support dynamic cursors! When a dynamic cursor is requested, you get a keyset cursor but the meaning is overloded as, "I'm using dynamic SQL" (as opposed to a prepared statement or stored proc) and the engine optimizes accordingly i.e. requesting a dynamic cursor is a good thing.
onedaywhen
A: 

are bhai koi to do answer kisi ko nahi aata kya

pankaj