RISC World

Using Powerbase - Part 4

by Derek Haslam

As promised in the last article, the main topics this month are:

  • Associating string operations and user functions with Computed fields
  • Using subsidiary indexes
  • Attaching external files to database records

Before proceeding, however, there is an updated version of Powerbase, PB834, on the CD. The changes from v.8.32 are minor but it's always best to use the latest version.

Using string operations in Composite fields

When a database contains the names of people we often want the names in different formats for different purposes. If the names supply the primary key of the database the surname usually comes first. Something like the first 4 letters of the surname plus the initial letter of the first name yields a suitable key for quickly retrieving records. e.g. John Smith might have 'Smith' in a Surname field and 'John' in a First name field, the primary key being SMITJ, which serves to distinguish John from (most) other Smiths. In an alphabetical list of names he would normally appear as Smith John but if we're addressing a letter to him we would prefer a mode of address such as 'Mr. J. Smith', or perhaps 'Dr. J. Smith', 'Rev. J. Smith' or whatever is most appropriate.

To illustrate this we need a new database. You can use the empty database !Names from the CD, if you wish, but you might care to get some more pratice using Powerbase by constructing it yourself. Five data fields, the first four of which are Editable, will be needed:

         Class        Type           Descriptor      Tag   Data length
Editable Unrestricted Surname SNAM 20 Editable Unrestricted First name FNAM 20 Editable Unrestricted Other names MNAM 20 Editable Unrestricted Title TITL 5 Computed Composite Address as ADDR 25

That last field is very important; it will allow us to re-jig the name into a format suitable for addressing a letter by making use of the data in the other fields. Just to make sure we get it right Fig.1 shows what the relevant part of the Field design window should look like when defining the field:

Fig.1 Designing the Computed field

Make sure you have Composite selected as the field type, not Calculated.

The number of different entries in the Title field will be quite small so you might add a Menu button to facilitate entry. Can you remember how to do that? The field type will be found in the Extra button class, it's Menu (field), not Menu (General) and you give it the same tag (TITL) as the associated data field. No descriptor is necessary.

Choose Default database from the main menu to create the empty database and put you into data-entry mode. Depending on how you've laid out the fields, your record window should look something like this:


If you did add the Menu button the next thing to do is construct the menu itself. Click SELECT on the button and it will tell you what to do. Be sure to change the menu title to something other than 'UserMenu' or you'll always get a text window to edit when you click the button instead of an actual menu. Below the title enter 'Mr.', 'Mrs.', 'Miss', 'Dr.', 'Rev.' etc., one to a line, then save the file with the supplied name.

Now for the Composite field. When the pointer is over this field it changes to a large cross indicating that this is not an Editable field. (Remember the 'pocket calcualator' pointer over the Calculated field added to the !Marks database last time?) What we want in the Composite field is the Title, followed by a space, then the initial letter of the First name, followed by a full-stop plus a space, and finally the Surname. Click MENU over the Composite field and choose Formula from the Field submenu. The writable icon will show 'ADDR=' and the right-hand side of the formula should be completed exactly as in Fig.3:

Fig.3 Entering the formula

The formula is quite a long one and isn't fully visible in the writable icon. The 'L' at far left is the final letter of TITL which comes immediately after the '='. The method used to strip the initial from FNAM will be familiar to anyone who has programmed in BASIC; the '1' after the comma means take the leftmost single letter of the field. The Fields menu button on the Formula window may be used to enter the field tags when the caret is at the appropriate place in the formula.

When you're sure the formula is correct click OK and you're ready to try it out. Notice how the contents of Address as change when you type Return after adding each piece of data. (If you type Return after entering the Title a new record will be displayed because Title is the last Editable field. To see the immediate effect of entering the Title type the up or down arrow instead of Return.)

If you change your mind about how you want to address people you can edit the formula. Access the Formula window again, delete everything up to the '=' and enter a new right-hand side as in Fig.4:

Fig.4 Altering the formula

When you enter new records the contents of Address as will be the First name followed by Surname with a single space between. But suppose we want to change all the existing records to this format? Nothing simpler! Go back to the Formula window, select the Recalculate existing records button and click OK. All the previously-entered records will be changed to the new format.

User functions in Composite fields

Using such a format raises another point: some people use a middle name as a regular form of address rather than their first given name. How can we accommodate this? It can be done by means of a User function. User functions are short program segments, written in BASIC and placed in a subdirectory UserFuncs inside the database. The actual writing of User functions is beyond the scope of this series but a number of useful ones, including the one required here, will be found on the CD in the zip file USERFUNCS. Proceed as follows:

  • Close the !Names database.
  • Shift-double-click on the !Names directory then open the UserFuncs subdirectory.
  • Open the USERFUNCS zip file.
  • Copy the BASIC file 'Name' into the database's UserFuncs subdirectory.
  • Re-open the !Names database.

Open the formula window and again delete up to the '='. If you now click the User functions menu button you will see the name of the single installed user function displayed as in Fig.5:

Fig.5 The User functions menu

This tells a BASIC programmer that the function FNUname takes three string variables as parmaeters. These are supplied by the Surname, First name and Other names fields respectively so what we actually need to put into the formula are the tags of these fields. When you choose the user function from the menu it is entered into the formula simply as 'FNUname()' and the caret is positioned between the parentheses. Enter SNAM,FNAM,MNAM (don't forget the commas!), select Recalculate existing records and click OK. Make sure the window looks as it does in Fig.6 before doing so:

Fig.6 A formula using a User function

If you now browse through the records you will notice no difference in Address as from what was there already! Bring up a record in which at least one name has been entered in Other names. (If there is more than one they must be separated by a space.) To make Address as use a name from this field place an asterisk immediately after the required name. e.g. If John Smith's full name is John Philip Aloysius Smith and he prefers to be called Philip, introduce an asterisk immediately after Philip in the Other names field. When you type Return Address as will change to 'Philip Smith'. If you'd placed the asterisk after 'Aloysius' it would have become 'Aloysius Smith'. (Users with some knowledge of programming in BASIC might like to examine how this simple user function works by loading the file 'Name' into their editor.)

Using subsidiary indexes

The only index we've encountered up to now is the primary key index; the one that every database must have in order to function at all. Powerbase allows you to create subsidiary indexes to present the records in a different order. You can have up to 10 subsidiary indexes, which ought to be plenty for most users, but the number may be increased if you wish by editing the file !Powerbase=>Resources=>Config. This is a text file which sets up many choices which need altering only rarely. The relevant item is the second one, with the token 'Keys' followed by a space and the number 10. Substitute a larger number if necessary and re-save the file.

To create a subsidiary index click MENU over the field you want to index and choose Create index from the Field submenu. In order to be indexable a field must be some sort of text field but needn't be an Editable one. You can, for example, index the Address as field in the !Names database. The window which appears is the same as the one used to define the primary key (Fig.7):

Fig.7 Indexing the Address as field

Note that the tag of the field over which you clicked MENU is already entered and the caret positioned in the Word icon. Pos contains 'L' (indicating that characters from the left-hand end of the chosen word will be used), and Chars contains the maximum length of the field which is probably far more than you want.

Assuming you have the name in the form given-name-plus-surname you might decide to take the first three letters of each to construct the key. To do so set up the window as in Fig.8:

Fig.8 The new key structure entered

(Although you accessed this window by indicating that you wanted to index the Address as field there is nothing to stop you defining a composite key using up to four fields, just as you can for the primary key.) Click Create and, when the process concludes, you will see that the Address as descriptor is now blue instead of black. This indicates that there is a key based on this field but it isn't the currently-selected key. To change to the new key click the tool-pane button bearing the representation of a key. Address as changes to red, indicating that it is now the selected key, and Surname becomes blue. If you have two or more subsidiary keys defined the 'key' button will cycle through them and the primary key. ADJUST cycles through the keys in the opposite order to SELECT. Since there are only two keys here, using either mouse button simply alternates them.

With the new key selected you will find that browsing and reporting accesses the records in an order determined by this key instead of the primary key. To retrieve an individual record after clicking the ? button you must now enter the appropriate subsidiary key in the Search window (Fig.9):

Fig.9 Searching on the new key

The name of the index containing these keys is 'ADDR+ADDR' because it is made up from two parts of the field whose tag is ADDR. Note, however, that bump icons are provided to allow you to search for a record using a key other than the selected one without actually changing the selected key.

The Index entry on the main menu leads to a submenu from which you can inspect the key-structure of the curent index, delete a subsidiary index (but not, of course, the primary key index!) and view the directory Indexes in which subsidiary indexes are stored. If you do delete an index it is removed from memory but not actually deleted from the disc. Instead the filename is prefixed with 'Del_' (and might also be truncated if your system can't use long filenames). You can revive a 'deleted' index by removing the prefix but you should only do so if no records have been added or deleted and no field on which the subsidary index is based has been altered.

Subsidiary indexes can, in some circumstances, speed up report-creation. This can be particularly noticeable in very large databases. The !Elements database in EXAMP will serve to demonstrate the principle, although it isn't nearly big enough to show the benefits.

  • Create a subsidiary index on the Groupfield. It consists of only one 'word' so there's no need to enter anything under Word. Don't make the index case-specific.
  • Don't make the new key the selected key: leave the primary key selected.
  • Select Name (plus any other fields you care to include) for reporting.
  • Make sure the Case specific button on the Match window is selected.
  • Create a report using GP=T as a search formula. If you do this by clicking the Print button on the Match window with ADJUST the window will remain open and indicate how long the report took.

Note the displayed time in the Match window. Next,click Old to retrieve the same search formula, deselect the Case specific button on the Match window, and again click the Print button with ADJUST. The displayed time should be less. On my 233 MHz RiscPC, with the first six fields selected the times are, respectively, 0.59 and 0.38 seconds. You may have spotted two other differences:

  • The report header in the first case says (as you'd expect) 'Ordered by: Primary key'. In the second case it says 'Ordered by: GP index', even though that wasn't the currently-selected index.
  • The small square icon next to the writable icon in the Match window changed briefly to display the number '1' (the number of the GP index) when creating the second report.

What's going on here, and why did deselecting Case specific make a difference? When Powerbase is given a straightforward search formula of the type tag=target, i.e there is no 'OR' element involved; an 'all or nothing' match of field with target is demanded, it looks to see whether the field is indexed. If it is, all the keys which match the target will be together, one after the other, in the subsidiary index and Powerbase can go straight to the beginning of this group of keys, ignoring all others which come before or after. Relieved of the necessity of scanning the entire subfile for matching records, Powerbase will complete the report more quickly but can only use this method if the case of the keys in the index agrees with the one to be matched.

By default, keys in an index are non-case-specific. Whatever the case of the letters in the fields from which the key is constructed, they will be forced to uppercase in the key itself. This frees the user from the need to think about case when searching for a record by key: whatever you type in the Search window is also forced to uppercase before comparing with the keys in the index. You can make keys case-specific (at the time the index is created; not afterwards) but you would then need to type a key exactly matching the case of letters when retrieving a record. When generating reports, however, case is usually more important so the Case specific on the Match window is normally selected. To force Powerbase to use a subsidiary index when creating a report you must set the Case specific switch on the Match window to be the same as on the Key structure window; either both must be selected or both deselected. It would have been possible to write Powerbase so that the button on the Match window was automatically set to agree with a subsidiary index when Powerbase was about to use the latter, but I considered the disadvantages to outwiegh the advantages. I'm willing to reconsider the matter, though, in the light of feedback from users.

Even in the example just demonstrated, where the targeted records amount to 30 out of 103, there is a time difference. If you wanted a report targetting 30 records out of 10,000 there would be a very dramatic difference.

Before leaving the subject of subsidiary indexes there are a couple more points worth making:

  • The primary key may not be null: at least one of the fields used in its construction must contain data. Subsidiary keys can, however, be null and it is often desirable to construct a subsidiary index on a field which is blank in a large number of records. Under these circumstances it may be be advisable to select the Omit null keys button before creating the index. Only those records which have data in at least one of the key fields will then be included in the index.
  • It is often useful to create a subsidiary index for just one purpose then delete it afterwards. In the !Marks database which we constructed near the end of the previous article you could create subsidiary indexes on each of the three mark fields so that lists of students could be printed in rank-order for each subject. It would actually be superfluous in this instance because a report in primary key order could be sorted on each mark column in turn, printing it out each time, but you'll get the idea.

Attaching external files to database records

Textual and numeric data in 'ordinary' database fields is stored in a file called Database inside the database's application directory. (It's a plain text file so you may load it into your favourite editor and examine it.) There are other types of field which are linked to graphics or text files, by which we mean a separate graphics or text file for each record. Because they aren't part of the Database file such fields are called External. There are, however, two levels of 'externalness'! Fields of the following types have their individual graphics or text files stored in a special system of subdirectories inside the database directory: they're 'external' to the Database file, but they do reside within the 'package' which makes up the database:

  • Text (Appears as a button on the record window with a small !Edit sprite)
  • Sprite (Also appears as a button, but with a small !Paint sprite)
  • Draw (Again, a button, but with a small !Draw sprite)
  • Text block (The text, or part of it, is actually displayed in a large text icon)
  • Picture (As above but the object is a sprite, actually displayed on the desktop)

Unzip the example database !Externals to see how this works. If you drop a text file onto the Text button the sprite on the button changes from an Edit to a text-file sprite. A similar thing happens when you drop a sprite file onto the Sprite button or a drawfile onto the Draw button. You will also find that these buttons will only accept the appropriate type of file: dropping sprite file onto a Text button has no effect. Once a file is linked to a button you can click the button to display the file in the appropriate editor (assuming the filer has 'seen' such an editor).

Dropping a text file onto the Text block icon displays the text, or as much of it as will fit. The limitations imposed by RISC OS on multi-line text icons mean that the lines are always centred and the text is not directly editable. Double-clicking over the icon will load the text into an editor and re-saving the text causes the Text block to update; there's no need to drop the updated file on the icon again. Picture fields behave in a similar way when sprites are dropped onto them but it is the user's responsibility to ensure that the icon is big enough to contain the sprite, otherwise it will overflow onto the rest of the window.

Where are these 'external' files actually stored? Shift-double-click on the !Externals directory and look inside. You will see a number of subdirectories with names like TBLKtext and TEXTtext. The first part of the name is the tag of the associated record field, the latter part tells us what type of file is stored. (NOTE: These directories won't be present until you have actually dropped an object on the button or rectangle concerned.) Look inside one of these directories and you will find a subdirectory called '0', inside which is another subdirectory called '0'! Inside the latter will be one or more Text, Sprite or Draw files called 'Rec0', 'Rec1' etc. indicating the record number with which the file is associated. This rather baffling directory structure arises from the 72-object directory limit on all versions of RISC OS prior to 4.02. When the bottom level directory gets full a new one called '1' is created in the level above. When that level becomes full of subdirectories one called '1' will be created immediately inside !Externals.TBLKtext or whatever.

Databases using External fields of the above types can become very large indeed - in actual disc size, not just in number of records. They do have the advantage that you know where everything is: their chief disadvantage is that, every time you drop a new file onto a field, you are making a copy of the original file. It would be nice if we could use a database to classify files (especially graphics files) without copying or moving them. We can do this with the final type of External field - Remote. Our last exercise this month will be to build a database which catalogues all the GIF files used as figures in this article.

We need only two fields: an Unrestricted field called something like 'Name' to act as the primary key field and hold an identifier for the picture, and a Remote field to which we will give the tag 'GIF'. Add a descriptor if you wish but it isn't really necessary. The record window of the empty database will look something like this:

Fig.10 A blank record

Enter a brief description - 'Fig.1' will do - then drag the file 'fig1/gif' from the HTML.POWERBASE.IMAGES directory and drop it on the large button. The down-pointing arrow will change to a GIF sprite:

Fig.9 A completed record

Create new records for the other GIFs in the same way. Clicking on the button will display the linked file if the filer has seen an appplication capable of displaying GIFs. Everyone should have ChangeFSI which can do so. David Pilling's excellent ImgMaster will also display GIFs. Moreover, if you click the Remote button with Ctrl-ADJUST and then browse through the records you will find that each image is displayed automatically as you go from record to record. Another Ctrl-ADJUST click turns off the auto-display feature.

The files have not been moved or copied from their original location: all Powerbase is doing is storing the pathname of the file so that it can be found wherever it is on the disc. You can use this method to catalogue files in directories scattered all over your hard-disc, or over several hard-discs, and the files need not be of the same type. The button displays the appropriate sprite for the file type, e.g. a JPEG sprite for a JPEG file. Shift-ADJUST over the button displays the pathname of the linked file, but it might look rather odd because it is a relative pathname showing where the file is in relation to the database. You can select the button with ADJUST to include the pathnames in a report

Well, that's all for this time. The main subjects of the next article will be mail-merging with Impression and Ovation Pro, and how to use Powerbase's script language to automate common tasks.

Derek Haslam