ExcelBanter

ExcelBanter (https://www.excelbanter.com/)
-   Excel Programming (https://www.excelbanter.com/excel-programming/)
-   -   Counting records with ADO (https://www.excelbanter.com/excel-programming/433951-counting-records-ado.html)

Geoff K

Counting records with ADO
 
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff


Jacob Skaria

Counting records with ADO
 
Wouldnt this work?

rsData2.RecordCount

If this post helps click Yes
---------------
Jacob Skaria


"Geoff K" wrote:

Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff


Geoff K

Counting records with ADO
 
I'm afraid not for the same reason, UsedRange.

Geoff

"Jacob Skaria" wrote:

Wouldnt this work?

rsData2.RecordCount

If this post helps click Yes
---------------
Jacob Skaria


"Geoff K" wrote:

Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff


Geoff K

Counting records with ADO
 
BTW The formatting of my example has not turned out as I wanted. It should
show 2 records under each field name not 6 under Field1.

Geoff

"Jacob Skaria" wrote:

Wouldnt this work?

rsData2.RecordCount

If this post helps click Yes
---------------
Jacob Skaria


"Geoff K" wrote:

Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff


Jacob Skaria

Counting records with ADO
 
Oops; i misunderstood your query. Using query may be you can get the number
of non-blank records for 1 column.. The below use the Worksheetfunction will
return the number of filled cells in ColB. ws is the worksheet object

Worksheetfunction.CountA(ws.Range("B:B"))

If this post helps click Yes
---------------
Jacob Skaria


"Geoff K" wrote:

BTW The formatting of my example has not turned out as I wanted. It should
show 2 records under each field name not 6 under Field1.

Geoff

"Jacob Skaria" wrote:

Wouldnt this work?

rsData2.RecordCount

If this post helps click Yes
---------------
Jacob Skaria


"Geoff K" wrote:

Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff


Geoff K

Counting records with ADO
 
I need to work with unopened wbooks.
In my example the real data ends at C10 but the UsedRange may be N20000. If
I count Field1 with SELECT COUNT(Field1) i will get count = 2 (the real
answer being 9).
Assuming I could count the blank records, and I cannot, I believe I would
get 19997 (20000 - header - real records).

The issue is how do i get the db cursor to stop at row 10 instead of 20000.

Geoff

"Jacob Skaria" wrote:

Oops; i misunderstood your query. Using query may be you can get the number
of non-blank records for 1 column.. The below use the Worksheetfunction will
return the number of filled cells in ColB. ws is the worksheet object

Worksheetfunction.CountA(ws.Range("B:B"))

If this post helps click Yes
---------------
Jacob Skaria


"Geoff K" wrote:

BTW The formatting of my example has not turned out as I wanted. It should
show 2 records under each field name not 6 under Field1.

Geoff

"Jacob Skaria" wrote:

Wouldnt this work?

rsData2.RecordCount

If this post helps click Yes
---------------
Jacob Skaria


"Geoff K" wrote:

Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff


keiji kounoike

Counting records with ADO
 
It seems Table1 to be a named range. What's the definition of Table1? Do
you want to know the last row number where data reside or a total number
of non blank data in each fields?

Keiji

Geoff K wrote:
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff


Geoff K

Counting records with ADO
 
Hi Keiji
Table1 is just an example name. In reality it represents the field name
range which varies from 1 wbook to another. Wbook1 could be "A1:T65536"
Wbook2 "A1:AM65536".
So SELECT [Fax] FROM [A1:AJ65536$]. "Fax" might be in "D1" or "Z1" or "N1".

I would like to find the last row of data in the whole wsheet but UsedRange
can sometimes stop me doing that accurately. My next thought was I can
easily count the data records in Fax with SELECT COUNT(Fax) and if I can then
count the blanks then that might just give me the true extent of the wsheet.
But I have my doubts because I think perhaps the 2 sums will still add up to
the same figure as the much exagerated UsedRange.

In my example I showed that 1 wbook I used had a UsedRange of AF50918 but
the real last cell was only S98. So lets say the real records in Fax were
72. What I was hoping to do was count the blanks in Fax and get 25. i.e.
header +72 +25 = 98. But what I fear will happen is header +72+50845 = 50918.

Hope this clarifies my problem.

Geoff.

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

It seems Table1 to be a named range. What's the definition of Table1? Do
you want to know the last row number where data reside or a total number
of non blank data in each fields?

Keiji

Geoff K wrote:
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff



Geoff K

Counting records with ADO
 
Hi Keiji
Table1 is just an example name. In reality it represents the field name
range which varies from 1 wbook to another. Wbook1 could be "A1:T65536"
Wbook2 "A1:AM65536".
So SELECT [Fax] FROM [A1:AJ65536$]. "Fax" might be in "D1" or "Z1" or "N1".

I would like to find the last row of data in the whole wsheet but UsedRange
can sometimes stop me doing that accurately. My next thought was I can
easily count the data records in Fax with SELECT COUNT(Fax) and if I can then
count the blanks then that might just give me the true extent of the wsheet.
But I have my doubts because I think perhaps the 2 sums will still add up to
the same figure as the much exagerated UsedRange.

In my example I showed that 1 wbook I used had a UsedRange of AF50918 but
the real last cell was only S98. So lets say the real records in Fax were
72. What I was hoping to do was count the blanks in Fax and get 25. i.e.
header +72 +25 = 98. But what I fear will happen is header +72+50845 = 50918.

Hope this clarifies my problem.

Geoff.

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

It seems Table1 to be a named range. What's the definition of Table1? Do
you want to know the last row number where data reside or a total number
of non blank data in each fields?

Keiji

Geoff K wrote:
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff



keiji kounoike

Counting records with ADO
 
Hi Geoff

Give this one a try. This would give you the last row of data in the
whole Worksheet. To be more accurate, the last row of data minus 1
because this assumes the first row is a header.

Sub ADOtest()
Dim oConn As ADODB.Connection
Dim Table1 As String
Dim Query2 As String

sSourceData = "c:\adodata.xls" '<<==Change to Your file's name
Table1 = "[Sheet1$]" '<<==Change to sheet's name plus "$"
Query2 = "Select * from " & Table1

Set oConn = New ADODB.Connection
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & sSourceData & ";" & _
"Extended Properties=""Excel 8.0;HDR=YES;"""

Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
oRS.Open Query2, oConn, adOpenStatic
MsgBox oRS.RecordCount

End Sub

Keiji

Geoff K wrote:
Hi Keiji
Table1 is just an example name. In reality it represents the field name
range which varies from 1 wbook to another. Wbook1 could be "A1:T65536"
Wbook2 "A1:AM65536".
So SELECT [Fax] FROM [A1:AJ65536$]. "Fax" might be in "D1" or "Z1" or "N1".

I would like to find the last row of data in the whole wsheet but UsedRange
can sometimes stop me doing that accurately. My next thought was I can
easily count the data records in Fax with SELECT COUNT(Fax) and if I can then
count the blanks then that might just give me the true extent of the wsheet.
But I have my doubts because I think perhaps the 2 sums will still add up to
the same figure as the much exagerated UsedRange.

In my example I showed that 1 wbook I used had a UsedRange of AF50918 but
the real last cell was only S98. So lets say the real records in Fax were
72. What I was hoping to do was count the blanks in Fax and get 25. i.e.
header +72 +25 = 98. But what I fear will happen is header +72+50845 = 50918.

Hope this clarifies my problem.

Geoff.

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

It seems Table1 to be a named range. What's the definition of Table1? Do
you want to know the last row number where data reside or a total number
of non blank data in each fields?

Keiji

Geoff K wrote:
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff


Geoff K

Counting records with ADO
 
Hi Keiji

Thank you for your responses so far.

FWIW please note in my first post the example 3 field table came out wrongly
formatted when posted. It was meant to show 2 records beneath each of the 3
fields but turned out as 6 under Field1.

I note your code requires references to ADODB whereas I use CreateObject.
Can I ask what you are using?

The wbook in question shows:
UsedRange last cell = AF50918
Real last cell = S98

I use szSQL1 to read and download field names to a temp wsheet using
szSQL1 = "SELECT * FROM [" & SourceRange$ & "];"
In this initial query SourceRange is defined as A1:IU1. Note IU and not
IV1. This overcomes the error 'Too many fields defined' which I have also
come across in some wbooks. Whilst not perfect I have never known all fields
to be used in any wbook so I have 'got away' with it so far.

Therefore from szSQL1 I know the real last field is in column S and I also
know if the wbook contains the required fields. I can then redefine
SourceRange in szSQL2 for this wbook as A1:S65536

Turning now to your suggestion, Debug returns
szSQL2 = SELECT COUNT(*) FROM [A1:S65536]
rsCount2 = rsData2(0) returns 50917
rsCount3 = rsData2.RecordCount returns 1

It does not seem to matter whether I use Sheet1$ or the defined range.

Start code:
Public Sub GetData(SourceFile As Variant, SourceRange As String, TargetRange
As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Long
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount

Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub
End code

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

Give this one a try. This would give you the last row of data in the
whole Worksheet. To be more accurate, the last row of data minus 1
because this assumes the first row is a header.

Sub ADOtest()
Dim oConn As ADODB.Connection
Dim Table1 As String
Dim Query2 As String

sSourceData = "c:\adodata.xls" '<<==Change to Your file's name
Table1 = "[Sheet1$]" '<<==Change to sheet's name plus "$"
Query2 = "Select * from " & Table1

Set oConn = New ADODB.Connection
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & sSourceData & ";" & _
"Extended Properties=""Excel 8.0;HDR=YES;"""

Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
oRS.Open Query2, oConn, adOpenStatic
MsgBox oRS.RecordCount

End Sub

Keiji

Geoff K wrote:
Hi Keiji
Table1 is just an example name. In reality it represents the field name
range which varies from 1 wbook to another. Wbook1 could be "A1:T65536"
Wbook2 "A1:AM65536".
So SELECT [Fax] FROM [A1:AJ65536$]. "Fax" might be in "D1" or "Z1" or "N1".

I would like to find the last row of data in the whole wsheet but UsedRange
can sometimes stop me doing that accurately. My next thought was I can
easily count the data records in Fax with SELECT COUNT(Fax) and if I can then
count the blanks then that might just give me the true extent of the wsheet.
But I have my doubts because I think perhaps the 2 sums will still add up to
the same figure as the much exagerated UsedRange.

In my example I showed that 1 wbook I used had a UsedRange of AF50918 but
the real last cell was only S98. So lets say the real records in Fax were
72. What I was hoping to do was count the blanks in Fax and get 25. i.e.
header +72 +25 = 98. But what I fear will happen is header +72+50845 = 50918.

Hope this clarifies my problem.

Geoff.

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

It seems Table1 to be a named range. What's the definition of Table1? Do
you want to know the last row number where data reside or a total number
of non blank data in each fields?

Keiji

Geoff K wrote:
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff



keiji kounoike

Counting records with ADO
 
Hi Geoff

I set the reference to some library in my macro. but using your macros,
I can't replicate your problem. First i put data into IV63556, then i
run the macro main below, it returns like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 65535 1
SELECT * FROM [Sheet1$A1:IU65536]; a 65535

after this, I delete data in IV63556 and run the macro main, i get the
result like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 33 1
SELECT * FROM [Sheet1$A1:IU65536]; a 33

I think you can't get a correct number of data with using RecordsCount
after having executed SELECT COUNT(*) FROM...
It always returns 1.

I added some lines in your code and run main. the result was like above.

Sub main()

GetData "c:\adodata.xls", "Sheet1$A1:IU65536", Range("a1")

End Sub


Public Sub GetData(SourceFile As Variant, SourceRange As String,
TargetRange As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Variant
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3


'Added these 6 lines from here
rsData2.Close
szSQL2 = "SELECT * FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub

Keiji

Geoff K wrote:
Hi Keiji

Thank you for your responses so far.

FWIW please note in my first post the example 3 field table came out wrongly
formatted when posted. It was meant to show 2 records beneath each of the 3
fields but turned out as 6 under Field1.

I note your code requires references to ADODB whereas I use CreateObject.
Can I ask what you are using?

The wbook in question shows:
UsedRange last cell = AF50918
Real last cell = S98

I use szSQL1 to read and download field names to a temp wsheet using
szSQL1 = "SELECT * FROM [" & SourceRange$ & "];"
In this initial query SourceRange is defined as A1:IU1. Note IU and not
IV1. This overcomes the error 'Too many fields defined' which I have also
come across in some wbooks. Whilst not perfect I have never known all fields
to be used in any wbook so I have 'got away' with it so far.

Therefore from szSQL1 I know the real last field is in column S and I also
know if the wbook contains the required fields. I can then redefine
SourceRange in szSQL2 for this wbook as A1:S65536

Turning now to your suggestion, Debug returns
szSQL2 = SELECT COUNT(*) FROM [A1:S65536]
rsCount2 = rsData2(0) returns 50917
rsCount3 = rsData2.RecordCount returns 1

It does not seem to matter whether I use Sheet1$ or the defined range.

Start code:
Public Sub GetData(SourceFile As Variant, SourceRange As String, TargetRange
As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Long
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount

Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub
End code

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

Give this one a try. This would give you the last row of data in the
whole Worksheet. To be more accurate, the last row of data minus 1
because this assumes the first row is a header.

Sub ADOtest()
Dim oConn As ADODB.Connection
Dim Table1 As String
Dim Query2 As String

sSourceData = "c:\adodata.xls" '<<==Change to Your file's name
Table1 = "[Sheet1$]" '<<==Change to sheet's name plus "$"
Query2 = "Select * from " & Table1

Set oConn = New ADODB.Connection
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & sSourceData & ";" & _
"Extended Properties=""Excel 8.0;HDR=YES;"""

Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
oRS.Open Query2, oConn, adOpenStatic
MsgBox oRS.RecordCount

End Sub

Keiji

Geoff K wrote:
Hi Keiji
Table1 is just an example name. In reality it represents the field name
range which varies from 1 wbook to another. Wbook1 could be "A1:T65536"
Wbook2 "A1:AM65536".
So SELECT [Fax] FROM [A1:AJ65536$]. "Fax" might be in "D1" or "Z1" or "N1".

I would like to find the last row of data in the whole wsheet but UsedRange
can sometimes stop me doing that accurately. My next thought was I can
easily count the data records in Fax with SELECT COUNT(Fax) and if I can then
count the blanks then that might just give me the true extent of the wsheet.
But I have my doubts because I think perhaps the 2 sums will still add up to
the same figure as the much exagerated UsedRange.

In my example I showed that 1 wbook I used had a UsedRange of AF50918 but
the real last cell was only S98. So lets say the real records in Fax were
72. What I was hoping to do was count the blanks in Fax and get 25. i.e.
header +72 +25 = 98. But what I fear will happen is header +72+50845 = 50918.

Hope this clarifies my problem.

Geoff.

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

It seems Table1 to be a named range. What's the definition of Table1? Do
you want to know the last row number where data reside or a total number
of non blank data in each fields?

Keiji

Geoff K wrote:
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff


Geoff K

Counting records with ADO
 
Hi Keiji
It is not easy to create a wbook where the UsedRange is out of line then
save it. I have the advantage (or not) in being able to work with 3 examples
sourced externally. It may be you are not able to replicate my problem
because you do not have a misaligned wbook to hand?

As to the issue I have with counting records - I have been able to count
both non-nulls and nulls in the wsheet. As I expected when the 2 counts are
summed the total is 50917 not 97 as I want.

First - Count(*). I don't beleive it actually counts anything. It gets
instead the UsedRange last row address and then makes an adjustment depending
on whether HDR is set as yes or no in the connection string.

Please see this MS response to a similar question
http://www.pcreview.co.uk/forums/thread-3284796.php

Second - RecordCount. In counting nulls or non-nulls it will will count to
EOF and that means the last record which in this case is at row 50918.

So at the moment I do not see any way of arriving at the correct record
count of 97 whern UsedRange is mis-aligned. Remember the objective is to
leave wbooks closed. It appears therefore that unless the UsedRange is
aligned with the real last cell there is no way a true count can ever be
obtained with these methods.

But I would love to be proved wrong. :)

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

I set the reference to some library in my macro. but using your macros,
I can't replicate your problem. First i put data into IV63556, then i
run the macro main below, it returns like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 65535 1
SELECT * FROM [Sheet1$A1:IU65536]; a 65535

after this, I delete data in IV63556 and run the macro main, i get the
result like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 33 1
SELECT * FROM [Sheet1$A1:IU65536]; a 33

I think you can't get a correct number of data with using RecordsCount
after having executed SELECT COUNT(*) FROM...
It always returns 1.

I added some lines in your code and run main. the result was like above.

Sub main()

GetData "c:\adodata.xls", "Sheet1$A1:IU65536", Range("a1")

End Sub


Public Sub GetData(SourceFile As Variant, SourceRange As String,
TargetRange As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Variant
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3


'Added these 6 lines from here
rsData2.Close
szSQL2 = "SELECT * FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub

Keiji

Geoff K wrote:
Hi Keiji

Thank you for your responses so far.

FWIW please note in my first post the example 3 field table came out wrongly
formatted when posted. It was meant to show 2 records beneath each of the 3
fields but turned out as 6 under Field1.

I note your code requires references to ADODB whereas I use CreateObject.
Can I ask what you are using?

The wbook in question shows:
UsedRange last cell = AF50918
Real last cell = S98

I use szSQL1 to read and download field names to a temp wsheet using
szSQL1 = "SELECT * FROM [" & SourceRange$ & "];"
In this initial query SourceRange is defined as A1:IU1. Note IU and not
IV1. This overcomes the error 'Too many fields defined' which I have also
come across in some wbooks. Whilst not perfect I have never known all fields
to be used in any wbook so I have 'got away' with it so far.

Therefore from szSQL1 I know the real last field is in column S and I also
know if the wbook contains the required fields. I can then redefine
SourceRange in szSQL2 for this wbook as A1:S65536

Turning now to your suggestion, Debug returns
szSQL2 = SELECT COUNT(*) FROM [A1:S65536]
rsCount2 = rsData2(0) returns 50917
rsCount3 = rsData2.RecordCount returns 1

It does not seem to matter whether I use Sheet1$ or the defined range.

Start code:
Public Sub GetData(SourceFile As Variant, SourceRange As String, TargetRange
As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Long
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount

Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub
End code

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

Give this one a try. This would give you the last row of data in the
whole Worksheet. To be more accurate, the last row of data minus 1
because this assumes the first row is a header.

Sub ADOtest()
Dim oConn As ADODB.Connection
Dim Table1 As String
Dim Query2 As String

sSourceData = "c:\adodata.xls" '<<==Change to Your file's name
Table1 = "[Sheet1$]" '<<==Change to sheet's name plus "$"
Query2 = "Select * from " & Table1

Set oConn = New ADODB.Connection
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & sSourceData & ";" & _
"Extended Properties=""Excel 8.0;HDR=YES;"""

Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
oRS.Open Query2, oConn, adOpenStatic
MsgBox oRS.RecordCount

End Sub

Keiji

Geoff K wrote:
Hi Keiji
Table1 is just an example name. In reality it represents the field name
range which varies from 1 wbook to another. Wbook1 could be "A1:T65536"
Wbook2 "A1:AM65536".
So SELECT [Fax] FROM [A1:AJ65536$]. "Fax" might be in "D1" or "Z1" or "N1".

I would like to find the last row of data in the whole wsheet but UsedRange
can sometimes stop me doing that accurately. My next thought was I can
easily count the data records in Fax with SELECT COUNT(Fax) and if I can then
count the blanks then that might just give me the true extent of the wsheet.
But I have my doubts because I think perhaps the 2 sums will still add up to
the same figure as the much exagerated UsedRange.

In my example I showed that 1 wbook I used had a UsedRange of AF50918 but
the real last cell was only S98. So lets say the real records in Fax were
72. What I was hoping to do was count the blanks in Fax and get 25. i.e.
header +72 +25 = 98. But what I fear will happen is header +72+50845 = 50918.

Hope this clarifies my problem.

Geoff.

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

It seems Table1 to be a named range. What's the definition of Table1? Do
you want to know the last row number where data reside or a total number
of non blank data in each fields?

Keiji

Geoff K wrote:
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff



keiji kounoike

Counting records with ADO
 
Hi Geoff

I've came to understand what you pointed. you are right about Usedrange
problem. I think this is not your option, but how about to reset
UsedRange before you run your macro. then, i think count(*) could return
a correct number. But To reset UsedRange, you need to open your data
file, so I think this is not the way you could accept.

Keiji

Geoff K wrote:
Hi Keiji
It is not easy to create a wbook where the UsedRange is out of line then
save it. I have the advantage (or not) in being able to work with 3 examples
sourced externally. It may be you are not able to replicate my problem
because you do not have a misaligned wbook to hand?

As to the issue I have with counting records - I have been able to count
both non-nulls and nulls in the wsheet. As I expected when the 2 counts are
summed the total is 50917 not 97 as I want.

First - Count(*). I don't beleive it actually counts anything. It gets
instead the UsedRange last row address and then makes an adjustment depending
on whether HDR is set as yes or no in the connection string.

Please see this MS response to a similar question
http://www.pcreview.co.uk/forums/thread-3284796.php

Second - RecordCount. In counting nulls or non-nulls it will will count to
EOF and that means the last record which in this case is at row 50918.

So at the moment I do not see any way of arriving at the correct record
count of 97 whern UsedRange is mis-aligned. Remember the objective is to
leave wbooks closed. It appears therefore that unless the UsedRange is
aligned with the real last cell there is no way a true count can ever be
obtained with these methods.

But I would love to be proved wrong. :)

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

I set the reference to some library in my macro. but using your macros,
I can't replicate your problem. First i put data into IV63556, then i
run the macro main below, it returns like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 65535 1
SELECT * FROM [Sheet1$A1:IU65536]; a 65535

after this, I delete data in IV63556 and run the macro main, i get the
result like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 33 1
SELECT * FROM [Sheet1$A1:IU65536]; a 33

I think you can't get a correct number of data with using RecordsCount
after having executed SELECT COUNT(*) FROM...
It always returns 1.

I added some lines in your code and run main. the result was like above.

Sub main()

GetData "c:\adodata.xls", "Sheet1$A1:IU65536", Range("a1")

End Sub


Public Sub GetData(SourceFile As Variant, SourceRange As String,
TargetRange As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Variant
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3


'Added these 6 lines from here
rsData2.Close
szSQL2 = "SELECT * FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub

Keiji

Geoff K wrote:
Hi Keiji

Thank you for your responses so far.

FWIW please note in my first post the example 3 field table came out wrongly
formatted when posted. It was meant to show 2 records beneath each of the 3
fields but turned out as 6 under Field1.

I note your code requires references to ADODB whereas I use CreateObject.
Can I ask what you are using?

The wbook in question shows:
UsedRange last cell = AF50918
Real last cell = S98

I use szSQL1 to read and download field names to a temp wsheet using
szSQL1 = "SELECT * FROM [" & SourceRange$ & "];"
In this initial query SourceRange is defined as A1:IU1. Note IU and not
IV1. This overcomes the error 'Too many fields defined' which I have also
come across in some wbooks. Whilst not perfect I have never known all fields
to be used in any wbook so I have 'got away' with it so far.

Therefore from szSQL1 I know the real last field is in column S and I also
know if the wbook contains the required fields. I can then redefine
SourceRange in szSQL2 for this wbook as A1:S65536

Turning now to your suggestion, Debug returns
szSQL2 = SELECT COUNT(*) FROM [A1:S65536]
rsCount2 = rsData2(0) returns 50917
rsCount3 = rsData2.RecordCount returns 1

It does not seem to matter whether I use Sheet1$ or the defined range.

Start code:
Public Sub GetData(SourceFile As Variant, SourceRange As String, TargetRange
As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Long
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount

Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub
End code

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

Give this one a try. This would give you the last row of data in the
whole Worksheet. To be more accurate, the last row of data minus 1
because this assumes the first row is a header.

Sub ADOtest()
Dim oConn As ADODB.Connection
Dim Table1 As String
Dim Query2 As String

sSourceData = "c:\adodata.xls" '<<==Change to Your file's name
Table1 = "[Sheet1$]" '<<==Change to sheet's name plus "$"
Query2 = "Select * from " & Table1

Set oConn = New ADODB.Connection
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & sSourceData & ";" & _
"Extended Properties=""Excel 8.0;HDR=YES;"""

Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
oRS.Open Query2, oConn, adOpenStatic
MsgBox oRS.RecordCount

End Sub

Keiji

Geoff K wrote:
Hi Keiji
Table1 is just an example name. In reality it represents the field name
range which varies from 1 wbook to another. Wbook1 could be "A1:T65536"
Wbook2 "A1:AM65536".
So SELECT [Fax] FROM [A1:AJ65536$]. "Fax" might be in "D1" or "Z1" or "N1".

I would like to find the last row of data in the whole wsheet but UsedRange
can sometimes stop me doing that accurately. My next thought was I can
easily count the data records in Fax with SELECT COUNT(Fax) and if I can then
count the blanks then that might just give me the true extent of the wsheet.
But I have my doubts because I think perhaps the 2 sums will still add up to
the same figure as the much exagerated UsedRange.

In my example I showed that 1 wbook I used had a UsedRange of AF50918 but
the real last cell was only S98. So lets say the real records in Fax were
72. What I was hoping to do was count the blanks in Fax and get 25. i.e.
header +72 +25 = 98. But what I fear will happen is header +72+50845 = 50918.

Hope this clarifies my problem.

Geoff.

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

It seems Table1 to be a named range. What's the definition of Table1? Do
you want to know the last row number where data reside or a total number
of non blank data in each fields?

Keiji

Geoff K wrote:
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff


Geoff K

Counting records with ADO
 
Hi Keiji
In my existing project I only use Query1 on unopened wbooks to determine if
they have the required fields. But once that is done I open each one for
processing. Part of the process is resetting the UsedRange, unhiding hidden
rows or columns, undoing any AutoFilter which may have been saved, undoing
any WordWraps, deleting end of line characters, terminating wbook links or
HyperLinks and other things before commencing the real task of extracting
required fields.

On that basis a folder of say 50 wbooks, each with an average of 1,000 rows
will take around 45 seconds to extract around 45,000 coherent rows.

With my wish-for algorithm of not opening any wbooks, the time is reduced to
around 20 seconds. Because this application needs to be run as often as it
does during the day and it is only part of a wider application you can
perhaps appreciate why it is worthwhile pursuing the option.

It is a real shame that wbooks are affected this way by a flawed UsedRange.
ADO and SQL are great, I can even read data when all data rows and columns
have been hidden! On an open wbook that would be impossible without
unhiding. I meet this misalignment of UsedRange in only 1 wbook out of 300
but when it does occur it has to be dealt with correctly.

Unfortunately after research and experimenting it now appears impossible to
reliably get a correct record count with either RecordCount or Count(*) when
the wbook is closed.

But thank you again for your help and participation.

Regards

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

I've came to understand what you pointed. you are right about Usedrange
problem. I think this is not your option, but how about to reset
UsedRange before you run your macro. then, i think count(*) could return
a correct number. But To reset UsedRange, you need to open your data
file, so I think this is not the way you could accept.

Keiji

Geoff K wrote:
Hi Keiji
It is not easy to create a wbook where the UsedRange is out of line then
save it. I have the advantage (or not) in being able to work with 3 examples
sourced externally. It may be you are not able to replicate my problem
because you do not have a misaligned wbook to hand?

As to the issue I have with counting records - I have been able to count
both non-nulls and nulls in the wsheet. As I expected when the 2 counts are
summed the total is 50917 not 97 as I want.

First - Count(*). I don't beleive it actually counts anything. It gets
instead the UsedRange last row address and then makes an adjustment depending
on whether HDR is set as yes or no in the connection string.

Please see this MS response to a similar question
http://www.pcreview.co.uk/forums/thread-3284796.php

Second - RecordCount. In counting nulls or non-nulls it will will count to
EOF and that means the last record which in this case is at row 50918.

So at the moment I do not see any way of arriving at the correct record
count of 97 whern UsedRange is mis-aligned. Remember the objective is to
leave wbooks closed. It appears therefore that unless the UsedRange is
aligned with the real last cell there is no way a true count can ever be
obtained with these methods.

But I would love to be proved wrong. :)

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

I set the reference to some library in my macro. but using your macros,
I can't replicate your problem. First i put data into IV63556, then i
run the macro main below, it returns like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 65535 1
SELECT * FROM [Sheet1$A1:IU65536]; a 65535

after this, I delete data in IV63556 and run the macro main, i get the
result like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 33 1
SELECT * FROM [Sheet1$A1:IU65536]; a 33

I think you can't get a correct number of data with using RecordsCount
after having executed SELECT COUNT(*) FROM...
It always returns 1.

I added some lines in your code and run main. the result was like above.

Sub main()

GetData "c:\adodata.xls", "Sheet1$A1:IU65536", Range("a1")

End Sub


Public Sub GetData(SourceFile As Variant, SourceRange As String,
TargetRange As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Variant
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3


'Added these 6 lines from here
rsData2.Close
szSQL2 = "SELECT * FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub

Keiji

Geoff K wrote:
Hi Keiji

Thank you for your responses so far.

FWIW please note in my first post the example 3 field table came out wrongly
formatted when posted. It was meant to show 2 records beneath each of the 3
fields but turned out as 6 under Field1.

I note your code requires references to ADODB whereas I use CreateObject.
Can I ask what you are using?

The wbook in question shows:
UsedRange last cell = AF50918
Real last cell = S98

I use szSQL1 to read and download field names to a temp wsheet using
szSQL1 = "SELECT * FROM [" & SourceRange$ & "];"
In this initial query SourceRange is defined as A1:IU1. Note IU and not
IV1. This overcomes the error 'Too many fields defined' which I have also
come across in some wbooks. Whilst not perfect I have never known all fields
to be used in any wbook so I have 'got away' with it so far.

Therefore from szSQL1 I know the real last field is in column S and I also
know if the wbook contains the required fields. I can then redefine
SourceRange in szSQL2 for this wbook as A1:S65536

Turning now to your suggestion, Debug returns
szSQL2 = SELECT COUNT(*) FROM [A1:S65536]
rsCount2 = rsData2(0) returns 50917
rsCount3 = rsData2.RecordCount returns 1

It does not seem to matter whether I use Sheet1$ or the defined range.

Start code:
Public Sub GetData(SourceFile As Variant, SourceRange As String, TargetRange
As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Long
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount

Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub
End code

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

Give this one a try. This would give you the last row of data in the
whole Worksheet. To be more accurate, the last row of data minus 1
because this assumes the first row is a header.

Sub ADOtest()
Dim oConn As ADODB.Connection
Dim Table1 As String
Dim Query2 As String

sSourceData = "c:\adodata.xls" '<<==Change to Your file's name
Table1 = "[Sheet1$]" '<<==Change to sheet's name plus "$"
Query2 = "Select * from " & Table1

Set oConn = New ADODB.Connection
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & sSourceData & ";" & _
"Extended Properties=""Excel 8.0;HDR=YES;"""

Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
oRS.Open Query2, oConn, adOpenStatic
MsgBox oRS.RecordCount

End Sub

Keiji

Geoff K wrote:
Hi Keiji
Table1 is just an example name. In reality it represents the field name
range which varies from 1 wbook to another. Wbook1 could be "A1:T65536"
Wbook2 "A1:AM65536".
So SELECT [Fax] FROM [A1:AJ65536$]. "Fax" might be in "D1" or "Z1" or "N1".

I would like to find the last row of data in the whole wsheet but UsedRange
can sometimes stop me doing that accurately. My next thought was I can
easily count the data records in Fax with SELECT COUNT(Fax) and if I can then
count the blanks then that might just give me the true extent of the wsheet.
But I have my doubts because I think perhaps the 2 sums will still add up to
the same figure as the much exagerated UsedRange.

In my example I showed that 1 wbook I used had a UsedRange of AF50918 but
the real last cell was only S98. So lets say the real records in Fax were
72. What I was hoping to do was count the blanks in Fax and get 25. i.e.
header +72 +25 = 98. But what I fear will happen is header +72+50845 = 50918.

Hope this clarifies my problem.

Geoff.

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

It seems Table1 to be a named range. What's the definition of Table1? Do
you want to know the last row number where data reside or a total number
of non blank data in each fields?

Keiji

Geoff K wrote:
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff



michdenis

Counting records with ADO
 
Hi Geoff,

Have you tested this ? Using 2 recordsets

'--------------------------------------------
Sub test()
Dim Conn As ADODB.Connection
Dim Rst As New ADODB.Recordset
Dim Rst1 As New ADODB.Recordset
Dim SheetName As String
Dim MyField As String
Dim Query As String, Query1 As String
Dim X As String
Dim Z As Long

SheetName = "Sheet1"
MyField = "ItsName" ' to determine

Set Conn = New ADODB.Connection
Conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & ThisWorkbook.FullName & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;"""

Query = "SELECT * FROM [" & SheetName & "$]" & _
" Where Not IsNull(" & MyField & ")"

Query1 = "SELECT * FROM [" & SheetName & "$]"

Rst.Open Query, Conn, adOpenStatic, adLockReadOnly
Rst1.Open Query1, Conn, adOpenStatic, adLockReadOnly

Rst.MoveLast
'I supposed a numeric field...
X = "" & MyField & "=" & Rst(0).Value

'Need a loop if duplicate in the field
Do While Rst1.EOF = False
Rst1.Find X
Z = Rst1.AbsolutePosition
Rst1.MoveNext
Loop
MsgBox "Last row of " & MyField & " is : " & Z + 1
Rst.Close: Rst1.Close
Conn.Close
Set Rst = Nothing: Set Rst1 = Nothing
Set Conn = Nothing

End Sub
'--------------------------------------------

Bye !




"Geoff K" a écrit dans le message de groupe de
discussion : ...
Hi Keiji
In my existing project I only use Query1 on unopened wbooks to determine if
they have the required fields. But once that is done I open each one for
processing. Part of the process is resetting the UsedRange, unhiding hidden
rows or columns, undoing any AutoFilter which may have been saved, undoing
any WordWraps, deleting end of line characters, terminating wbook links or
HyperLinks and other things before commencing the real task of extracting
required fields.

On that basis a folder of say 50 wbooks, each with an average of 1,000 rows
will take around 45 seconds to extract around 45,000 coherent rows.

With my wish-for algorithm of not opening any wbooks, the time is reduced to
around 20 seconds. Because this application needs to be run as often as it
does during the day and it is only part of a wider application you can
perhaps appreciate why it is worthwhile pursuing the option.

It is a real shame that wbooks are affected this way by a flawed UsedRange.
ADO and SQL are great, I can even read data when all data rows and columns
have been hidden! On an open wbook that would be impossible without
unhiding. I meet this misalignment of UsedRange in only 1 wbook out of 300
but when it does occur it has to be dealt with correctly.

Unfortunately after research and experimenting it now appears impossible to
reliably get a correct record count with either RecordCount or Count(*) when
the wbook is closed.

But thank you again for your help and participation.

Regards

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

I've came to understand what you pointed. you are right about Usedrange
problem. I think this is not your option, but how about to reset
UsedRange before you run your macro. then, i think count(*) could return
a correct number. But To reset UsedRange, you need to open your data
file, so I think this is not the way you could accept.

Keiji

Geoff K wrote:
Hi Keiji
It is not easy to create a wbook where the UsedRange is out of line then
save it. I have the advantage (or not) in being able to work with 3 examples
sourced externally. It may be you are not able to replicate my problem
because you do not have a misaligned wbook to hand?

As to the issue I have with counting records - I have been able to count
both non-nulls and nulls in the wsheet. As I expected when the 2 counts are
summed the total is 50917 not 97 as I want.

First - Count(*). I don't beleive it actually counts anything. It gets
instead the UsedRange last row address and then makes an adjustment depending
on whether HDR is set as yes or no in the connection string.

Please see this MS response to a similar question
http://www.pcreview.co.uk/forums/thread-3284796.php

Second - RecordCount. In counting nulls or non-nulls it will will count to
EOF and that means the last record which in this case is at row 50918.

So at the moment I do not see any way of arriving at the correct record
count of 97 whern UsedRange is mis-aligned. Remember the objective is to
leave wbooks closed. It appears therefore that unless the UsedRange is
aligned with the real last cell there is no way a true count can ever be
obtained with these methods.

But I would love to be proved wrong. :)

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

I set the reference to some library in my macro. but using your macros,
I can't replicate your problem. First i put data into IV63556, then i
run the macro main below, it returns like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 65535 1
SELECT * FROM [Sheet1$A1:IU65536]; a 65535

after this, I delete data in IV63556 and run the macro main, i get the
result like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 33 1
SELECT * FROM [Sheet1$A1:IU65536]; a 33

I think you can't get a correct number of data with using RecordsCount
after having executed SELECT COUNT(*) FROM...
It always returns 1.

I added some lines in your code and run main. the result was like above.

Sub main()

GetData "c:\adodata.xls", "Sheet1$A1:IU65536", Range("a1")

End Sub


Public Sub GetData(SourceFile As Variant, SourceRange As String,
TargetRange As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Variant
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3


'Added these 6 lines from here
rsData2.Close
szSQL2 = "SELECT * FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub

Keiji

Geoff K wrote:
Hi Keiji

Thank you for your responses so far.

FWIW please note in my first post the example 3 field table came out wrongly
formatted when posted. It was meant to show 2 records beneath each of the 3
fields but turned out as 6 under Field1.

I note your code requires references to ADODB whereas I use CreateObject.
Can I ask what you are using?

The wbook in question shows:
UsedRange last cell = AF50918
Real last cell = S98

I use szSQL1 to read and download field names to a temp wsheet using
szSQL1 = "SELECT * FROM [" & SourceRange$ & "];"
In this initial query SourceRange is defined as A1:IU1. Note IU and not
IV1. This overcomes the error 'Too many fields defined' which I have also
come across in some wbooks. Whilst not perfect I have never known all fields
to be used in any wbook so I have 'got away' with it so far.

Therefore from szSQL1 I know the real last field is in column S and I also
know if the wbook contains the required fields. I can then redefine
SourceRange in szSQL2 for this wbook as A1:S65536

Turning now to your suggestion, Debug returns
szSQL2 = SELECT COUNT(*) FROM [A1:S65536]
rsCount2 = rsData2(0) returns 50917
rsCount3 = rsData2.RecordCount returns 1

It does not seem to matter whether I use Sheet1$ or the defined range.

Start code:
Public Sub GetData(SourceFile As Variant, SourceRange As String, TargetRange
As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Long
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount

Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub
End code

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

Give this one a try. This would give you the last row of data in the
whole Worksheet. To be more accurate, the last row of data minus 1
because this assumes the first row is a header.

Sub ADOtest()
Dim oConn As ADODB.Connection
Dim Table1 As String
Dim Query2 As String

sSourceData = "c:\adodata.xls" '<<==Change to Your file's name
Table1 = "[Sheet1$]" '<<==Change to sheet's name plus "$"
Query2 = "Select * from " & Table1

Set oConn = New ADODB.Connection
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & sSourceData & ";" & _
"Extended Properties=""Excel 8.0;HDR=YES;"""

Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
oRS.Open Query2, oConn, adOpenStatic
MsgBox oRS.RecordCount

End Sub

Keiji

Geoff K wrote:
Hi Keiji
Table1 is just an example name. In reality it represents the field name
range which varies from 1 wbook to another. Wbook1 could be "A1:T65536"
Wbook2 "A1:AM65536".
So SELECT [Fax] FROM [A1:AJ65536$]. "Fax" might be in "D1" or "Z1" or "N1".

I would like to find the last row of data in the whole wsheet but UsedRange
can sometimes stop me doing that accurately. My next thought was I can
easily count the data records in Fax with SELECT COUNT(Fax) and if I can then
count the blanks then that might just give me the true extent of the wsheet.
But I have my doubts because I think perhaps the 2 sums will still add up to
the same figure as the much exagerated UsedRange.

In my example I showed that 1 wbook I used had a UsedRange of AF50918 but
the real last cell was only S98. So lets say the real records in Fax were
72. What I was hoping to do was count the blanks in Fax and get 25. i.e.
header +72 +25 = 98. But what I fear will happen is header +72+50845 = 50918.

Hope this clarifies my problem.

Geoff.

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

It seems Table1 to be a named range. What's the definition of Table1? Do
you want to know the last row number where data reside or a total number
of non blank data in each fields?

Keiji

Geoff K wrote:
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff



keiji kounoike

Counting records with ADO
 
Hi Geoff

I'm not sure that I've understood your situation correctly. And you
might not want to have this one because this one also needs to open a
file. but what if getting the last row before applying your macro? the
code is like this.

Sub Getlastrow_Workbook()
Dim oAPP As Object
Dim WK As Workbook
Dim SourceFile As String
Dim shname As String

SourceFile = "C:\adodata.xls"
shname = "Sheet1"

Set oAPP = CreateObject("Excel.Application")
oAPP.Visible = False
Set WK = oAPP.Workbooks.Open(SourceFile)
lastrow = WK.Worksheets(shname).Cells.Find(What:="*", _
After:=WK.Worksheets(shname).Range("A1"), _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
oAPP.DisplayAlerts = False
WK.Close
MsgBox lastrow
Set oAPP = Nothing
End Sub

Keiji

Geoff K wrote:
Hi Keiji
In my existing project I only use Query1 on unopened wbooks to determine if
they have the required fields. But once that is done I open each one for
processing. Part of the process is resetting the UsedRange, unhiding hidden
rows or columns, undoing any AutoFilter which may have been saved, undoing
any WordWraps, deleting end of line characters, terminating wbook links or
HyperLinks and other things before commencing the real task of extracting
required fields.

On that basis a folder of say 50 wbooks, each with an average of 1,000 rows
will take around 45 seconds to extract around 45,000 coherent rows.

With my wish-for algorithm of not opening any wbooks, the time is reduced to
around 20 seconds. Because this application needs to be run as often as it
does during the day and it is only part of a wider application you can
perhaps appreciate why it is worthwhile pursuing the option.

It is a real shame that wbooks are affected this way by a flawed UsedRange.
ADO and SQL are great, I can even read data when all data rows and columns
have been hidden! On an open wbook that would be impossible without
unhiding. I meet this misalignment of UsedRange in only 1 wbook out of 300
but when it does occur it has to be dealt with correctly.

Unfortunately after research and experimenting it now appears impossible to
reliably get a correct record count with either RecordCount or Count(*) when
the wbook is closed.

But thank you again for your help and participation.

Regards

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

I've came to understand what you pointed. you are right about Usedrange
problem. I think this is not your option, but how about to reset
UsedRange before you run your macro. then, i think count(*) could return
a correct number. But To reset UsedRange, you need to open your data
file, so I think this is not the way you could accept.

Keiji

Geoff K wrote:
Hi Keiji
It is not easy to create a wbook where the UsedRange is out of line then
save it. I have the advantage (or not) in being able to work with 3 examples
sourced externally. It may be you are not able to replicate my problem
because you do not have a misaligned wbook to hand?

As to the issue I have with counting records - I have been able to count
both non-nulls and nulls in the wsheet. As I expected when the 2 counts are
summed the total is 50917 not 97 as I want.

First - Count(*). I don't beleive it actually counts anything. It gets
instead the UsedRange last row address and then makes an adjustment depending
on whether HDR is set as yes or no in the connection string.

Please see this MS response to a similar question
http://www.pcreview.co.uk/forums/thread-3284796.php

Second - RecordCount. In counting nulls or non-nulls it will will count to
EOF and that means the last record which in this case is at row 50918.

So at the moment I do not see any way of arriving at the correct record
count of 97 whern UsedRange is mis-aligned. Remember the objective is to
leave wbooks closed. It appears therefore that unless the UsedRange is
aligned with the real last cell there is no way a true count can ever be
obtained with these methods.

But I would love to be proved wrong. :)

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

I set the reference to some library in my macro. but using your macros,
I can't replicate your problem. First i put data into IV63556, then i
run the macro main below, it returns like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 65535 1
SELECT * FROM [Sheet1$A1:IU65536]; a 65535

after this, I delete data in IV63556 and run the macro main, i get the
result like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 33 1
SELECT * FROM [Sheet1$A1:IU65536]; a 33

I think you can't get a correct number of data with using RecordsCount
after having executed SELECT COUNT(*) FROM...
It always returns 1.

I added some lines in your code and run main. the result was like above.

Sub main()

GetData "c:\adodata.xls", "Sheet1$A1:IU65536", Range("a1")

End Sub


Public Sub GetData(SourceFile As Variant, SourceRange As String,
TargetRange As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Variant
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3


'Added these 6 lines from here
rsData2.Close
szSQL2 = "SELECT * FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub

Keiji

Geoff K wrote:
Hi Keiji

Thank you for your responses so far.

FWIW please note in my first post the example 3 field table came out wrongly
formatted when posted. It was meant to show 2 records beneath each of the 3
fields but turned out as 6 under Field1.

I note your code requires references to ADODB whereas I use CreateObject.
Can I ask what you are using?

The wbook in question shows:
UsedRange last cell = AF50918
Real last cell = S98

I use szSQL1 to read and download field names to a temp wsheet using
szSQL1 = "SELECT * FROM [" & SourceRange$ & "];"
In this initial query SourceRange is defined as A1:IU1. Note IU and not
IV1. This overcomes the error 'Too many fields defined' which I have also
come across in some wbooks. Whilst not perfect I have never known all fields
to be used in any wbook so I have 'got away' with it so far.

Therefore from szSQL1 I know the real last field is in column S and I also
know if the wbook contains the required fields. I can then redefine
SourceRange in szSQL2 for this wbook as A1:S65536

Turning now to your suggestion, Debug returns
szSQL2 = SELECT COUNT(*) FROM [A1:S65536]
rsCount2 = rsData2(0) returns 50917
rsCount3 = rsData2.RecordCount returns 1

It does not seem to matter whether I use Sheet1$ or the defined range.

Start code:
Public Sub GetData(SourceFile As Variant, SourceRange As String, TargetRange
As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Long
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount

Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub
End code

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

Give this one a try. This would give you the last row of data in the
whole Worksheet. To be more accurate, the last row of data minus 1
because this assumes the first row is a header.

Sub ADOtest()
Dim oConn As ADODB.Connection
Dim Table1 As String
Dim Query2 As String

sSourceData = "c:\adodata.xls" '<<==Change to Your file's name
Table1 = "[Sheet1$]" '<<==Change to sheet's name plus "$"
Query2 = "Select * from " & Table1

Set oConn = New ADODB.Connection
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & sSourceData & ";" & _
"Extended Properties=""Excel 8.0;HDR=YES;"""

Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
oRS.Open Query2, oConn, adOpenStatic
MsgBox oRS.RecordCount

End Sub

Keiji

Geoff K wrote:
Hi Keiji
Table1 is just an example name. In reality it represents the field name
range which varies from 1 wbook to another. Wbook1 could be "A1:T65536"
Wbook2 "A1:AM65536".
So SELECT [Fax] FROM [A1:AJ65536$]. "Fax" might be in "D1" or "Z1" or "N1".

I would like to find the last row of data in the whole wsheet but UsedRange
can sometimes stop me doing that accurately. My next thought was I can
easily count the data records in Fax with SELECT COUNT(Fax) and if I can then
count the blanks then that might just give me the true extent of the wsheet.
But I have my doubts because I think perhaps the 2 sums will still add up to
the same figure as the much exagerated UsedRange.

In my example I showed that 1 wbook I used had a UsedRange of AF50918 but
the real last cell was only S98. So lets say the real records in Fax were
72. What I was hoping to do was count the blanks in Fax and get 25. i.e.
header +72 +25 = 98. But what I fear will happen is header +72+50845 = 50918.

Hope this clarifies my problem.

Geoff.

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

It seems Table1 to be a named range. What's the definition of Table1? Do
you want to know the last row number where data reside or a total number
of non blank data in each fields?

Keiji

Geoff K wrote:
Hi
I'm using ADO to retrieve data from unopened wbooks. One of the first tasks
is to get the number of original records from the wsheet but I have hit a
UsedRange
problem.

I've used this for speed:
Query2 = "SELECT COUNT(*) FROM Table1;"
rsData2.Open Query2, rsCon, adOpenStatic
rsCount2 = rsData2(0)

It generally succeeds and returns an accurate count but occasionally it
fails because a wbook has been saved with a huge UsedRange which does not
match the real data. For example doing a Ctrl + End on one wbook showed the
last cell as AF50918 whereas the real last cell was only S98.

I have tried getting the max value using a loop with
Query2 = "SELECT COUNT( column ) FROM Table1;"

But this will not necessarily return the correct count. For example it will
return the count as 2 instead of 6 from this data.
Field1 Field2 Field3
xxx
xxx
xxx
xxx
xxx
xxx

So how do I get the real count when dealing with a UsedRange problem in an
unopened wbook?

T.I.A.

Geoff


Geoff K

Counting records with ADO
 
Hi michdenis

I get an error at Rst1.Find X

X returns a value in Field 0. Whilst Rst.MoveLast is used I am not able to
verify that is working as I believe is intended because that field contains
records which coincidently are all the same so I'm not able to tell if X is
the first or last record. (I do not want to change wbook values for testing
as that will reset the out of line UsedRange)

Geoff

"michdenis" wrote:

Hi Geoff,

Have you tested this ? Using 2 recordsets

'--------------------------------------------
Sub test()
Dim Conn As ADODB.Connection
Dim Rst As New ADODB.Recordset
Dim Rst1 As New ADODB.Recordset
Dim SheetName As String
Dim MyField As String
Dim Query As String, Query1 As String
Dim X As String
Dim Z As Long

SheetName = "Sheet1"
MyField = "ItsName" ' to determine

Set Conn = New ADODB.Connection
Conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & ThisWorkbook.FullName & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;"""

Query = "SELECT * FROM [" & SheetName & "$]" & _
" Where Not IsNull(" & MyField & ")"

Query1 = "SELECT * FROM [" & SheetName & "$]"

Rst.Open Query, Conn, adOpenStatic, adLockReadOnly
Rst1.Open Query1, Conn, adOpenStatic, adLockReadOnly

Rst.MoveLast
'I supposed a numeric field...
X = "" & MyField & "=" & Rst(0).Value

'Need a loop if duplicate in the field
Do While Rst1.EOF = False
Rst1.Find X
Z = Rst1.AbsolutePosition
Rst1.MoveNext
Loop
MsgBox "Last row of " & MyField & " is : " & Z + 1
Rst.Close: Rst1.Close
Conn.Close
Set Rst = Nothing: Set Rst1 = Nothing
Set Conn = Nothing

End Sub
'--------------------------------------------

Bye !



michdenis

Counting records with ADO
 
There is an exemple in this file : http://cjoint.com/?jDndv2hXXE



"Geoff K" a écrit dans le message de groupe de
discussion : ...
Hi michdenis

I get an error at Rst1.Find X

X returns a value in Field 0. Whilst Rst.MoveLast is used I am not able to
verify that is working as I believe is intended because that field contains
records which coincidently are all the same so I'm not able to tell if X is
the first or last record. (I do not want to change wbook values for testing
as that will reset the out of line UsedRange)

Geoff

"michdenis" wrote:

Hi Geoff,

Have you tested this ? Using 2 recordsets

'--------------------------------------------
Sub test()
Dim Conn As ADODB.Connection
Dim Rst As New ADODB.Recordset
Dim Rst1 As New ADODB.Recordset
Dim SheetName As String
Dim MyField As String
Dim Query As String, Query1 As String
Dim X As String
Dim Z As Long

SheetName = "Sheet1"
MyField = "ItsName" ' to determine

Set Conn = New ADODB.Connection
Conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & ThisWorkbook.FullName & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;"""

Query = "SELECT * FROM [" & SheetName & "$]" & _
" Where Not IsNull(" & MyField & ")"

Query1 = "SELECT * FROM [" & SheetName & "$]"

Rst.Open Query, Conn, adOpenStatic, adLockReadOnly
Rst1.Open Query1, Conn, adOpenStatic, adLockReadOnly

Rst.MoveLast
'I supposed a numeric field...
X = "" & MyField & "=" & Rst(0).Value

'Need a loop if duplicate in the field
Do While Rst1.EOF = False
Rst1.Find X
Z = Rst1.AbsolutePosition
Rst1.MoveNext
Loop
MsgBox "Last row of " & MyField & " is : " & Z + 1
Rst.Close: Rst1.Close
Conn.Close
Set Rst = Nothing: Set Rst1 = Nothing
Set Conn = Nothing

End Sub
'--------------------------------------------

Bye !



Geoff K

Counting records with ADO
 
Hi Keiji
I already have an algorthm which works very well on open workbooks.
I am attempting to save running time by NOT opening wbooks.

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

I'm not sure that I've understood your situation correctly. And you
might not want to have this one because this one also needs to open a
file. but what if getting the last row before applying your macro? the
code is like this.

Sub Getlastrow_Workbook()
Dim oAPP As Object
Dim WK As Workbook
Dim SourceFile As String
Dim shname As String

SourceFile = "C:\adodata.xls"
shname = "Sheet1"

Set oAPP = CreateObject("Excel.Application")
oAPP.Visible = False
Set WK = oAPP.Workbooks.Open(SourceFile)
lastrow = WK.Worksheets(shname).Cells.Find(What:="*", _
After:=WK.Worksheets(shname).Range("A1"), _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
oAPP.DisplayAlerts = False
WK.Close
MsgBox lastrow
Set oAPP = Nothing
End Sub

Keiji

Geoff K wrote:
Hi Keiji
In my existing project I only use Query1 on unopened wbooks to determine if
they have the required fields. But once that is done I open each one for
processing. Part of the process is resetting the UsedRange, unhiding hidden
rows or columns, undoing any AutoFilter which may have been saved, undoing
any WordWraps, deleting end of line characters, terminating wbook links or
HyperLinks and other things before commencing the real task of extracting
required fields.

On that basis a folder of say 50 wbooks, each with an average of 1,000 rows
will take around 45 seconds to extract around 45,000 coherent rows.

With my wish-for algorithm of not opening any wbooks, the time is reduced to
around 20 seconds. Because this application needs to be run as often as it
does during the day and it is only part of a wider application you can
perhaps appreciate why it is worthwhile pursuing the option.

It is a real shame that wbooks are affected this way by a flawed UsedRange.
ADO and SQL are great, I can even read data when all data rows and columns
have been hidden! On an open wbook that would be impossible without
unhiding. I meet this misalignment of UsedRange in only 1 wbook out of 300
but when it does occur it has to be dealt with correctly.

Unfortunately after research and experimenting it now appears impossible to
reliably get a correct record count with either RecordCount or Count(*) when
the wbook is closed.

But thank you again for your help and participation.

Regards

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

I've came to understand what you pointed. you are right about Usedrange
problem. I think this is not your option, but how about to reset
UsedRange before you run your macro. then, i think count(*) could return
a correct number. But To reset UsedRange, you need to open your data
file, so I think this is not the way you could accept.

Keiji

Geoff K wrote:
Hi Keiji
It is not easy to create a wbook where the UsedRange is out of line then
save it. I have the advantage (or not) in being able to work with 3 examples
sourced externally. It may be you are not able to replicate my problem
because you do not have a misaligned wbook to hand?

As to the issue I have with counting records - I have been able to count
both non-nulls and nulls in the wsheet. As I expected when the 2 counts are
summed the total is 50917 not 97 as I want.

First - Count(*). I don't beleive it actually counts anything. It gets
instead the UsedRange last row address and then makes an adjustment depending
on whether HDR is set as yes or no in the connection string.

Please see this MS response to a similar question
http://www.pcreview.co.uk/forums/thread-3284796.php

Second - RecordCount. In counting nulls or non-nulls it will will count to
EOF and that means the last record which in this case is at row 50918.

So at the moment I do not see any way of arriving at the correct record
count of 97 whern UsedRange is mis-aligned. Remember the objective is to
leave wbooks closed. It appears therefore that unless the UsedRange is
aligned with the real last cell there is no way a true count can ever be
obtained with these methods.

But I would love to be proved wrong. :)

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

I set the reference to some library in my macro. but using your macros,
I can't replicate your problem. First i put data into IV63556, then i
run the macro main below, it returns like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 65535 1
SELECT * FROM [Sheet1$A1:IU65536]; a 65535

after this, I delete data in IV63556 and run the macro main, i get the
result like this

SELECT COUNT(*) FROM [Sheet1$A1:IU65536]; 33 1
SELECT * FROM [Sheet1$A1:IU65536]; a 33

I think you can't get a correct number of data with using RecordsCount
after having executed SELECT COUNT(*) FROM...
It always returns 1.

I added some lines in your code and run main. the result was like above.

Sub main()

GetData "c:\adodata.xls", "Sheet1$A1:IU65536", Range("a1")

End Sub


Public Sub GetData(SourceFile As Variant, SourceRange As String,
TargetRange As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Variant
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3


'Added these 6 lines from here
rsData2.Close
szSQL2 = "SELECT * FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount
Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub

Keiji

Geoff K wrote:
Hi Keiji

Thank you for your responses so far.

FWIW please note in my first post the example 3 field table came out wrongly
formatted when posted. It was meant to show 2 records beneath each of the 3
fields but turned out as 6 under Field1.

I note your code requires references to ADODB whereas I use CreateObject.
Can I ask what you are using?

The wbook in question shows:
UsedRange last cell = AF50918
Real last cell = S98

I use szSQL1 to read and download field names to a temp wsheet using
szSQL1 = "SELECT * FROM [" & SourceRange$ & "];"
In this initial query SourceRange is defined as A1:IU1. Note IU and not
IV1. This overcomes the error 'Too many fields defined' which I have also
come across in some wbooks. Whilst not perfect I have never known all fields
to be used in any wbook so I have 'got away' with it so far.

Therefore from szSQL1 I know the real last field is in column S and I also
know if the wbook contains the required fields. I can then redefine
SourceRange in szSQL2 for this wbook as A1:S65536

Turning now to your suggestion, Debug returns
szSQL2 = SELECT COUNT(*) FROM [A1:S65536]
rsCount2 = rsData2(0) returns 50917
rsCount3 = rsData2.RecordCount returns 1

It does not seem to matter whether I use Sheet1$ or the defined range.

Start code:
Public Sub GetData(SourceFile As Variant, SourceRange As String, TargetRange
As Range)

Dim rsCon As Object
Dim rsData2 As Object
Dim szConnect As String
Dim szSQL2 As String
Dim rsCount2 As Long
Dim rsCount3 As Long

szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"

Set rsCon = CreateObject("ADODB.Connection")
Set rsData2 = CreateObject("ADODB.Recordset")
rsCon.Open szConnect

szSQL2 = "SELECT COUNT(*) FROM [" & SourceRange$ & "];"
rsData2.Open szSQL2, rsCon, adOpenStatic
rsCount2 = rsData2(0)
rsCount3 = rsData2.RecordCount

Debug.Print szSQL2; vbTab; rsCount2; vbTab; rsCount3

If rsData2.State = adStateOpen Then rsData2.Close
Set rsData2 = Nothing
rsCon.Close
Set rsCon = Nothing

End Sub
End code

Geoff


"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

Give this one a try. This would give you the last row of data in the
whole Worksheet. To be more accurate, the last row of data minus 1
because this assumes the first row is a header.

Sub ADOtest()
Dim oConn As ADODB.Connection
Dim Table1 As String
Dim Query2 As String

sSourceData = "c:\adodata.xls" '<<==Change to Your file's name
Table1 = "[Sheet1$]" '<<==Change to sheet's name plus "$"
Query2 = "Select * from " & Table1

Set oConn = New ADODB.Connection
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & sSourceData & ";" & _
"Extended Properties=""Excel 8.0;HDR=YES;"""

Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
oRS.Open Query2, oConn, adOpenStatic
MsgBox oRS.RecordCount

End Sub

Keiji

Geoff K wrote:
Hi Keiji
Table1 is just an example name. In reality it represents the field name
range which varies from 1 wbook to another. Wbook1 could be "A1:T65536"
Wbook2 "A1:AM65536".
So SELECT [Fax] FROM [A1:AJ65536$]. "Fax" might be in "D1" or "Z1" or "N1".

I would like to find the last row of data in the whole wsheet but UsedRange
can sometimes stop me doing that accurately. My next thought was I can
easily count the data records in Fax with SELECT COUNT(Fax) and if I can then
count the blanks then that might just give me the true extent of the wsheet.
But I have my doubts because I think perhaps the 2 sums will still add up to
the same figure as the much exagerated UsedRange.

In my example I showed that 1 wbook I used had a UsedRange of AF50918 but
the real last cell was only S98. So lets say the real records in Fax were
72. What I was hoping to do was count the blanks in Fax and get 25. i.e.


Geoff K

Counting records with ADO
 
Hi Keiji
I already have an algorthm which works very well on open wbooks. It is very
quick. My post is about saving running time by NOT opening and closing
wbooks.
I will now experiment with the suggestion from michdenis.
Thank you for your contribution.
Geoff

Geoff K

Counting records with ADO
 
Hi
Thanks for the example. I have got it to work on a single field, the error
was caused simply by reading a text field not a numeric. :)

I now need to expand it to obtain the last row of the whole table. However
this wbook UsedRange is so bloated, AF50918 compared to S98, and the loop
used on duplicates is very slow even on a single field. I fear it will undo
all the run time advantage of not opening and closing the wbook.

But it is at least one way and worth further experimentation.

Geoff

"michdenis" wrote:

There is an exemple in this file : http://cjoint.com/?jDndv2hXXE



michdenis

Counting records with ADO
 
There is an another approch to solve your problem.

You can use a "Name" of the collection "Names" to store
"the" last row of your sheet each time your workbook is
Deactivated... or Closed (Sub Workbook_BeforeClose(Cancel As Boolean)

Insert in the ThisWorkbook of your projectvba of your workbook
this code :
'-----------------------------
Private Sub Workbook_Deactivate()
Dim LastRow As String
On Error Resume Next
With Sheet1
LastRow = .Cells.Find(What:="*", _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
On Error GoTo 0
End With

ThisWorkbook.Names.Add "LastRow", LastRow, False
End Sub
'-----------------------------

Now, from any other workbook, you can easily read the value
of this "NAME" using this type of code :
'---------------------------------
Sub Test()
Dim LastRow As Long
LastRow = Application.ExecuteExcel4Macro("'C:\MyPath\MyWorkb ook.xls'!LastRow")
End Sub
'---------------------------------

A fast and simple approach !



"Geoff K" a écrit dans le message de groupe de
discussion : ...
Hi
Thanks for the example. I have got it to work on a single field, the error
was caused simply by reading a text field not a numeric. :)

I now need to expand it to obtain the last row of the whole table. However
this wbook UsedRange is so bloated, AF50918 compared to S98, and the loop
used on duplicates is very slow even on a single field. I fear it will undo
all the run time advantage of not opening and closing the wbook.

But it is at least one way and worth further experimentation.

Geoff

"michdenis" wrote:

There is an exemple in this file :
http://cjoint.com/?jDndv2hXXE


Geoff K

Counting records with ADO
 
Hi
I was able to get the UsedRange code to loop through all fields for all
wbooks in a folder but as I suspected the bloat caused it to run very slowly.
But the method does work with a bit of adaptation.

Excel4Macro seems to hold great promise:
In my set up the parent is an Add-in. I use a temp wbook to dump data
extracts into for further work. The target wbooks are never opened.

If I put the "LastRow" code into the Add-in ThisWorkBook mod and put "Test"
into a std module of the Add-in, save and reopen then run "Test" I get a
GetOpenFilename dialog. If I navigate to a wbook and select a wbook it
errors with Type Mismatch.

If I substitute this in "Test" I don't get the dialog but it still errors
with Type Mismatch.
LastRow =
Application.ExecuteExcel4Macro("'C:\Path\[Dels.xls]Sheet1'!LastRow").

I then changed Dim LastRow As String in "LastRow" to a Long but it did not
make any difference because "Test" errored out.

I'm not able to get beyond this error to test if LastRow will work. Not
being familiar with Excel4Macro yet - can LastRow in the line above refer to
another procedure rather than a range?

Geoff

"michdenis" wrote:

There is an another approch to solve your problem.

You can use a "Name" of the collection "Names" to store
"the" last row of your sheet each time your workbook is
Deactivated... or Closed (Sub Workbook_BeforeClose(Cancel As Boolean)

Insert in the ThisWorkbook of your projectvba of your workbook
this code :
'-----------------------------
Private Sub Workbook_Deactivate()
Dim LastRow As String
On Error Resume Next
With Sheet1
LastRow = .Cells.Find(What:="*", _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
On Error GoTo 0
End With

ThisWorkbook.Names.Add "LastRow", LastRow, False
End Sub
'-----------------------------

Now, from any other workbook, you can easily read the value
of this "NAME" using this type of code :
'---------------------------------
Sub Test()
Dim LastRow As Long
LastRow = Application.ExecuteExcel4Macro("'C:\MyPath\MyWorkb ook.xls'!LastRow")
End Sub
'---------------------------------

A fast and simple approach !



"Geoff K" a écrit dans le message de groupe de
discussion : ...
Hi
Thanks for the example. I have got it to work on a single field, the error
was caused simply by reading a text field not a numeric. :)

I now need to expand it to obtain the last row of the whole table. However
this wbook UsedRange is so bloated, AF50918 compared to S98, and the loop
used on duplicates is very slow even on a single field. I fear it will undo
all the run time advantage of not opening and closing the wbook.

But it is at least one way and worth further experimentation.

Geoff

"michdenis" wrote:

There is an exemple in this file :
http://cjoint.com/?jDndv2hXXE


keiji kounoike

Counting records with ADO
 
I think that you need to write Sub Workbook_Deactivate() into your data
book and the Sub Test() into the parent. In my thought, your data file
must be opened when you use ExecuteExcel4Macro. so, I think this is not
so efficient as you think.

Keiji

Geoff K wrote:
Hi
I was able to get the UsedRange code to loop through all fields for all
wbooks in a folder but as I suspected the bloat caused it to run very slowly.
But the method does work with a bit of adaptation.

Excel4Macro seems to hold great promise:
In my set up the parent is an Add-in. I use a temp wbook to dump data
extracts into for further work. The target wbooks are never opened.

If I put the "LastRow" code into the Add-in ThisWorkBook mod and put "Test"
into a std module of the Add-in, save and reopen then run "Test" I get a
GetOpenFilename dialog. If I navigate to a wbook and select a wbook it
errors with Type Mismatch.

If I substitute this in "Test" I don't get the dialog but it still errors
with Type Mismatch.
LastRow =
Application.ExecuteExcel4Macro("'C:\Path\[Dels.xls]Sheet1'!LastRow").

I then changed Dim LastRow As String in "LastRow" to a Long but it did not
make any difference because "Test" errored out.

I'm not able to get beyond this error to test if LastRow will work. Not
being familiar with Excel4Macro yet - can LastRow in the line above refer to
another procedure rather than a range?

Geoff

"michdenis" wrote:

There is an another approch to solve your problem.

You can use a "Name" of the collection "Names" to store
"the" last row of your sheet each time your workbook is
Deactivated... or Closed (Sub Workbook_BeforeClose(Cancel As Boolean)

Insert in the ThisWorkbook of your projectvba of your workbook
this code :
'-----------------------------
Private Sub Workbook_Deactivate()
Dim LastRow As String
On Error Resume Next
With Sheet1
LastRow = .Cells.Find(What:="*", _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
On Error GoTo 0
End With

ThisWorkbook.Names.Add "LastRow", LastRow, False
End Sub
'-----------------------------

Now, from any other workbook, you can easily read the value
of this "NAME" using this type of code :
'---------------------------------
Sub Test()
Dim LastRow As Long
LastRow = Application.ExecuteExcel4Macro("'C:\MyPath\MyWorkb ook.xls'!LastRow")
End Sub
'---------------------------------

A fast and simple approach !



"Geoff K" a écrit dans le message de groupe de
discussion : ...
Hi
Thanks for the example. I have got it to work on a single field, the error
was caused simply by reading a text field not a numeric. :)

I now need to expand it to obtain the last row of the whole table. However
this wbook UsedRange is so bloated, AF50918 compared to S98, and the loop
used on duplicates is very slow even on a single field. I fear it will undo
all the run time advantage of not opening and closing the wbook.

But it is at least one way and worth further experimentation.

Geoff

"michdenis" wrote:

There is an exemple in this file :
http://cjoint.com/?jDndv2hXXE


Geoff K

Counting records with ADO
 
Hi Keiji
You are correct. It appears as if the method will only work if a name is
created in the target wbook and it remains open.

However I came across this link
http://spreadsheetpage.com/index.php...a_closed_file/

This works when both Function and calling sub are installed in a std mod in
my Add-in and the target wbook is closed.

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

I think that you need to write Sub Workbook_Deactivate() into your data
book and the Sub Test() into the parent. In my thought, your data file
must be opened when you use ExecuteExcel4Macro. so, I think this is not
so efficient as you think.

Keiji



michdenis

Counting records with ADO
 
This precedure can read the value of a name in a closed Workbook
But you need to open the workbook to create a name !

'------------------------------------
Sub Test()
Dim LastRow As Long
LastRow = Application.ExecuteExcel4Macro("'C:\MyPath\MyWorkb ook.xls'!LastRow")
End Sub
'------------------------------------




"Geoff K" a écrit dans le message de groupe de
discussion : ...
Hi Keiji
You are correct. It appears as if the method will only work if a name is
created in the target wbook and it remains open.

However I came across this link
http://spreadsheetpage.com/index.php...a_closed_file/

This works when both Function and calling sub are installed in a std mod in
my Add-in and the target wbook is closed.

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

I think that you need to write Sub Workbook_Deactivate() into your data
book and the Sub Test() into the parent. In my thought, your data file
must be opened when you use ExecuteExcel4Macro. so, I think this is not
so efficient as you think.

Keiji



keiji kounoike

Counting records with ADO
 
Hi Geoff

But I wonder how you can get the last row using the method you
introduced? According to your comments on my previous post, it's not
important whether to open a file or not. I think my Sub
Getlastrow_Workbook() in my previous post is fast enough to get a last
row. you could change this sub to function with arguments if you need
to, say, loop many files.

Keiji

Geoff K wrote:
Hi Keiji
You are correct. It appears as if the method will only work if a name is
created in the target wbook and it remains open.

However I came across this link
http://spreadsheetpage.com/index.php...a_closed_file/

This works when both Function and calling sub are installed in a std mod in
my Add-in and the target wbook is closed.

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

I think that you need to write Sub Workbook_Deactivate() into your data
book and the Sub Test() into the parent. In my thought, your data file
must be opened when you use ExecuteExcel4Macro. so, I think this is not
so efficient as you think.

Keiji



Geoff K

Counting records with ADO
 
Hi Keiji

I can only repeat, I do NOT want to open target wbooks.
On your Find(*) method I have been using the same for a long time in many of
my procedures. I know it works. But I do NOT want to open target wbooks -
it wastes a lot of time.

I am now researching another method please see my latest post "Getting data
from a closed wbook".

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

But I wonder how you can get the last row using the method you
introduced? According to your comments on my previous post, it's not
important whether to open a file or not. I think my Sub
Getlastrow_Workbook() in my previous post is fast enough to get a last
row. you could change this sub to function with arguments if you need
to, say, loop many files.

Keiji



michdenis

Counting records with ADO
 
There are not many solutions.

If you do not want to open your workbook
And
If you use ADO (activex data object) to erase data in your database
you will necessary end up with empty rows. ADO can erase data
but cannot delete any row. If you don't open your database
you have one solution left...that one you found with ADO sooner this week.
based on my example.


"Geoff K" a écrit dans le message de groupe de
discussion : ...
Hi Keiji

I can only repeat, I do NOT want to open target wbooks.
On your Find(*) method I have been using the same for a long time in many of
my procedures. I know it works. But I do NOT want to open target wbooks -
it wastes a lot of time.

I am now researching another method please see my latest post "Getting data
from a closed wbook".

Geoff

"keiji kounoike" <"kounoike A | T ma.Pik" wrote:

Hi Geoff

But I wonder how you can get the last row using the method you
introduced? According to your comments on my previous post, it's not
important whether to open a file or not. I think my Sub
Getlastrow_Workbook() in my previous post is fast enough to get a last
row. you could change this sub to function with arguments if you need
to, say, loop many files.

Keiji



Geoff K

Counting records with ADO
 
Thanks for your continued interest.

As I have said I use an Add-in + a temp wbk + a log wbk. The project
interrogates multiple wbks in a folder. ADO is used to read the field names
of all wbks to assess if each has the required field names (which may be in
any order). At the same time I want to get the last row used to calculate
the number of original records.

If all wbooks are ok then I use something like SELECT fld1, fld2, fld10,
fld22 etc FROM wsheet1 WHERE NOT ISNULL fld2 to extract data to the tmp wbk.
Processing continues and results are appended to the log for all wbks in the
folder.

Unless there is an abnormality there is no need to ever return to a wbk once
it has been processed. All that is required is the data within.

The wbooks are supplied from outside sources. I have no control over the
presentation or quality - and believe me when I say some are absolutely
apalling - some arrive without field names!

I am now examining the possibility of a wsheet formula which could be
inserted into the hidden sheet of my Add-in. Interestingly
=MATCH(99^99,'C:\Path\[File.xls]Sheet1'!A:A) returns the last used row in col
A if it is a numeric field. Using MTCH "ZZZ" does the same for a text field.
All I need do then is loop through the known fields from my first SELECT
statement to get the last used row of each wbk. But right now I have to
construct the loop and test. However there is a snag to this - the wbk with
the huge bloat goes into an infinite loop but curiously another wbk with a
smaller misaligned UsedRange does not.

If you have any views on this new approach they would be welcome and thank
you again for the continued interest.

Geoff

"michdenis" wrote:

There are not many solutions.

If you do not want to open your workbook
And
If you use ADO (activex data object) to erase data in your database
you will necessary end up with empty rows. ADO can erase data
but cannot delete any row. If you don't open your database
you have one solution left...that one you found with ADO sooner this week.
based on my example.




All times are GMT +1. The time now is 09:26 AM.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
ExcelBanter.com