views:

2980

answers:

5

Hi,

Is there a way in MS access to return a dataset between a specific index?

So lets say my dataset is:

rank | first_name | age
  1       Max       23
  2       Bob       40
  3       Sid       25
  4       Billy     18
  5       Sally     19

But I only want to return those records between 'rank' 2 and 4, so my results set is Bob, Sid and Billy? However, Rank is not part of the table, and this should be generated when the query is run. Why don't I use an autogenerated number, because if a record is deleted, this will be inconsistent, and what if I wanted the results in reverse!

This obviously very simple, and the reason I ask is because I am working on a product catalogue and I am looking for a more efficient way of paging through the returned dataset, so if I only return 1 page worth of data from the database this is obviously going to be quicker then return a complete set of 3000 records and then having to subselect from that set!

Thanks R.

+1  A: 

Original suggestion:

SELECT * from table where rank BETWEEN 2 and 4;

Modified after comment, that rank is not existing in structure:

Select top 100 * from table;

And if you want to choose subsequent results, you can choose the ID of the last record from the first query, say it was ID 101, and use a WHERE clause to get the next 100;

Select top 100 * from table where ID > 100;

But these won't give you what you're looking for either, I bet.

Sev
Nope, you misunderstood my question, rank is not part of the dataset.
flavour404
A: 

If I understand you correctly, there is ionly first_name and age columns in your table. If this is the case, then there is no way to return Bob, Sid, and Billy with a single query. Unless you do something like

SELECT * FROM Table 
WHERE FirstName = 'Bob'
OR FirstName = 'Sid'
OR FirstName = 'Billy'

But I think that this is not what you are looking for.

This is because SQL databases make no guarantee as to the order that the data will come out of the database unless you specify an ORDER BY clause. It will usually come out in the same order it was added, but there are no guarantees, and once you get a lot of rows in your table, there's a reasonably high probability that they won't come out in the order you put them in.

As a side note, you should probably add a "rank" column (this column is usually called id) to your table, and make it an auto incrementing integer (see Access documentation), so that you can do the query mentioned by Sev. It's also important to have a primary key so that you can be certain which rows are being updated when you are running an update query, or which rows are being deleted when you run a delete query. For example, if you had 2 people named Max, and they were both 23, how you delete 1 row without deleting the other. If you had another auto incrementing unique column in there, you could specify the unique ID in your query to delete only one.

[ADDITION]

Upon reading your comment, If you add an autoincrement field, and want to read 3 rows, and you know the ID of the first row you want to read, then you can use "TOP" to read 3 rows.

Assuming your data looks like this

 ID   | first_name | age
  1       Max       23
  2       Bob       40
  6       Sid       25
  8       Billy     18
  15      Sally     19

You can wuery Bob, Sid and Billy with the following QUERY.

SELECT TOP 3 FirstName, Age 
From Table 
WHERE ID >= 2
ORDER BY ID
Kibbee
Hi, thanks. I obvioulsy have explained the problem poorly. I cannot use the auto number function because if a row is deleted then a gap will be left. Lets say I query my database and I get a dataset back containinag 40 rows, so rank would be numbered 1 to 40, but from that I only want results 10 - 15. Think of it this way, when you return results to a web site you ahve a paging function, lets say you only have 10 results displayed on that page so I wouldn't want the whole dataset, but instead a subset of 10 records with which to populate my page.
flavour404
See my addition to see how this can be done when you have an ID column.
Kibbee
+1  A: 

How are you calculating rank? I assume you are basing it on some data in another dataset somewhere. If so, create a function, do a table join, or do something that can calculate rank based on values in other table(s), then you can do queries based on the rank() function.

For example:

select *
from table
where rank() between 2 and 4

If you are not calculating rank based on some data somewhere, there really isn't a way to write this query, and you might as well be returning three random rows from the table.

ecounysis
A: 

Unfortunately the LIMIT keyword isn't available in MS Access -- that's what is used in MySQL for a multi-page presentation. If you can write an order key into the results table, then you can use it something like this:

SELECT TOP 25 MyOrder, Etc FROM Table1 WHERE MyOrder in (SELECT TOP 55 MyOrder FROM Table1 ORDER BY MyOrder DESC) ORDER BY MyOrder ASCENDING

Smandoli
At 24 hours of posting, it appears this is two problems: establishing a "Mid" slice of the recordset, which might be solvable with nesting and use of the TOP keyword; and generating a number-series on the fly, which seems impossible. And there's the mystery of what 'rank' means.
Smandoli
+1  A: 

I think you need to use a correlated subquery to calculate the rank on the fly e.g. I'm guessing the rank is based on name:

SELECT T1.first_name, T1.age, 
       (
        SELECT COUNT(*) + 1
          FROM MyTable AS T2
         WHERE T1.first_name > T2.first_name
       ) AS rank
FROM MyTable AS T1;

The bad news is the Access data engine is poorly optimized for this kind of query; in my experience, performace will start to noticeably degrade beyond a few hundred rows.

If it is not possible to maintain the rank on the db side of the house (e.g. high insertion environment) consider doing the paging on the client side. For example, an ADO classic recordset object has properties to support paging (PageCount, PageSize, AbsolutePage, etc), something for which DAO recordsets (being of an older vintage) have no support.

As always, you'll have to perform your own timings but I suspect that when there are, say, 10K rows you will find it faster to take on the overhead of fetching all the rows to an ADO recordset then finding the page (then perhaps fabricate smaller ADO recordset consisting of just that page's worth of rows) than it is to perform a correlated subquery to only fetch the number of rows for the page.

onedaywhen