开发者

SQL find next record by non-unique field

I need to find the next record in a database with (say) a given Surname. So if the user is looking at A Smith, the query would return either the Next A Smith, or B Smith

the solution is probably similar to that discussed here : selecting subsequent records arbitrarily with limit but using an ODBC 2.0 compliant database rather than mysql.

At the moment I have a procedural solution, but it is very slow. Is there a more elegant approach which uses only basic SQL ?

Sample Data in "appropriate" order

recnum, surname, firstnames 
1000,smith,andrew 
1320,smith,andrew 
1340,smith,andrew 
14,smith,anton 
17,smith,anton 
2000,smith,brian 
2030,smith,brian 
1017,smith,brianally 

I would have the recnum of the current record and need to find the next in the above (which is ordered on surname, forenames, recnum) In this example the case for 1320 is easy, b开发者_运维百科ut 1340 makes it harder!


Given your sample data and assuming that at any point in the process you have the "recnum" value available for the current record, it would be possible to query for the next value by using a series of up to three queries. If you think of the three pieces of data (surname, firstname, recnum) as a composite index, then you want to find the record that comes next in index order. So assuming you have the three pieces of data from the current record, run this:

select top 1 surname, firstname, recnum from Table
    where surname = @CurrentLast and 
    firstname = @CurrentFirst and 
    Recnum > @CurrRec
    order by surname, firstname, recnum

If that is empty, then run this:

select top 1 surname, firstname, recnum from Table
    where surname = @CurrentLast and 
    firstname > @CurrentFirst
    order by surname, firstname, recnum

And finally, if that is empty:

select top 1 surname, firstname, recnum from Table
    where surname > @CurrentLast
    order by surname, firstname, recnum

If the three fields are indexed, it should be reasonably efficient. It would also be possible to use a single query such as the following (syntax probably wrong), but it would require a composite index on all three fields in order to be efficient.

select top 1 surname, firstname, recnum from Table
    where surname+firstname+convert(recnum,char) > @CombinedValue
    order by surname, firstname, recnum

If recnum refers to a physical record number in the underlying data and if the SQL engine uses the record number as the tie breaker when other conditions match in sorting, then I believe that recnum could be left out of the order by clauses.


SQL is intended to work with and return set of data. In fact, one of the points Coad (or one of the gurus of relationalism anyway) uses to describe a relational database is that there is no "next record" -- the concept shouldn't even exist.

As such, from the viewpoint of SQL, what you should do is create a set that contains the data you want in the order you want:

select * from YourTable
    where LastName = @whatever
    order by FirstName

Then, if you want to work with one record at a time, you probably want a cursor into that data set. Using that, you'll just look at a record, and when you advance the cursor to the next record, it'll be the one that should be next.


If by 'next' you mean alphabetical on first name, then try:

  Select * From Table T
  Where lastName = @GivenSurname
     And firstName = 
      (Select Min(FirstName)
       From Table 
       Where LastName = T.LastName
          And FirstName > @GivenFirstName)

If there might be more than one record with this same first name and last Name, and if you have a surrogate Primary Key, then you can arbitrarilly pick one of them by using this:

  Select * From Table T1
  Where lastName = @GivenSurname
     And PK = 
      (Select Min(PK) From Table T2
       Where LastName = T1.LastName
         And FirstName =
          (Select Min(FirstName)
           From Table
           Where LastName = T1.LastName
                And FirstName > @GivenFirstName))


Does "no state preservation" mean that you can't store any data at all, even pre-caching? In other words, query

SELECT recnum FROM my_table ORDER BY surname, firstname

Use getrows to store that in a local array. Then iterate through that array, each time executing the prepared statement

SELECT surname, firstname FROM my_table WHERE recnum = ?

That will almost certainly be slower than querying it all at once, but it will satisfy your goal.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜