Search code examples
databasedelphiloopsrecords

Following Records


I've been having a little problem with getting my program to follow records through a database dependent on the values within the record, simply put, this is what I'm trying to achieve.

This is a simplified version of the table I'm working with:

Record Name  |  Val1  | Val2  | Link |  Prev Link |
Rec1         |   5    |  3    | Rec2 |            |
Rec2         |   2    |  4    | Rec6 |  Rec1      |
Rec3         |   1    |  8    | Rec4 |            |
Rec4         |   1    |  1    |      |  Rec3      |
Rec5         |   8    |  3    |      |            |
Rec6         |   9    |  3    |      |  Rec2      |

My program needs to go through the above table, save the information against one particular record, go to it's linked record, clear the values of the previous record and then add them onto the newer record (it should keep doing this till it reaches the end of the chain), as an example here is what should happen after running my program.

Record Name  |  Val1  | Val2  | Link |  Prev Link |
Rec1         |   0    |  0    | Rec2 |            |
Rec2         |   0    |  0    | Rec6 |  Rec1      |
Rec3         |   0    |  0    | Rec4 |            |
Rec4         |   2    |  9    |      |  Rec3      |
Rec5         |   8    |  3    |      |            |
Rec6         |   16   |  10   |      |  Rec2      |

The current procedure I am using can be found at the following location: http://pastebin.com/A10hW0C6

The main problem I am facing is that I cannot get the program to go through each record, follow any links and then return to the place that it left off to make sure it doesn't miss any, also how can I make the program ignore records that it has already been over as part of a loop?

Any help would be appreciated :)


Solution

  • Well, what you can do is to have a seperate query to hold the start-of-the-link records, such as:

    qry1.sql := 'select * from table where prev_link is null;';
    

    This gives

    Record Name  |  Val1  | Val2  | Link |  Prev Link |       
    Rec1         |   5    |  3    | Rec2 |            |       
    Rec3         |   1    |  8    | Rec4 |            |       
    Rec5         |   8    |  3    |      |            |       
    

    Then you can follow the result data set, seek/locate on the other query (query2), and apply your processing logic there.

    By the time you finished with the result date set, you are done. This, of course, assuming that your data is legit, i.e. no broken links, no circular links, etc.

    Some enhancement. You can add a column called 'status' to reflect the status of the record. For example, status = 0 means 'Unprocessed', '1' means processed, '2' means broken links, '3' means circular link, etc. You can start by populating all status column with 0 (unprocessed).

    If you can not find the record by seeking/locating it in the 'Link' column (maybe somehow get deleted), then you can flag the status to '2'.

    Each time you follow a link, keep a track of the followed record. You can use a list, for example. Before following a record in the 'Link' column, check the list. If the record is in the list, then you have a circular link. Stop following, mark the status to '3' (circular link), clear the list, and start with the next record in query1. Dealing with circular link is important, otherwise your program can stuck on it (never ended).

    When you finish processing a chain of links, then flag status to '1' to all records in the list.

    You can make use of database transaction (begin transaction ...end transaction), so when you encounter deadlink or circular link down the link-chain, you can rollback the changed values, and flag the status accordingly.

    After you finish, you can check the status column. If all '1' means all good (processed). If not then you can decide what to do next.

    The column status can be used to filtered out already processed records on another sub sequent operations, so the query above can be altered:

    qry1.sql := 'select * from table where prev_link is null and status = 0;';
    

    Of course this is a preliminary strategy, and you can modify it to suit you.