|
This page describes the structure and naming conventions of database tables in a Pedserve system. It is not essential that you know this, but it is useful if you want to extend the database e.g. by adding user-defined fields or records. Databases, Tablesets and Table SuffixesA Pedserve system consists of a MySQL database containing various tables organized into groups we call tablesets. There is a mandatory tableset called Each tableset comprises 1 or more actual database tables. Each table is named using a consistent naming scheme - comprising the tableset name, an underscore (' The way to think about tablesets is to treat them as groups of related tables, following a consistent table naming scheme. The tableset is merely a concept used within Pedserve; as far as MySQL is concerned there is no such thing as a tableset - it just deals with tables. The
Each animal tableset comprises the following tables (replace 'FOO' with the name of your animal tableset):
* The use of the family, mating, inbreeding and user-defined tables is entirely optional. Note also that they are not supported by Pedserve Standard Edition; you need Pedserve Pro, Advanced, or Developer Edition. Field (Column) Naming ConventionsThe fields (columns) within a table all have names that start with the table suffix, followed by an underscore. E.g. the users table, Every table is expected to have a non-null, integer primary key field which must have the name Some tables include foreign key fields - fields whose value is the primary key of some other row either in the same table or a different table. E.g. an animals table (table suffix Here are some examples of foreign key fields:
Chained Field NamesAt this point you could be forgiven for wondering why such a naming convention is used, especially for primary and foreign key fields. The answer lies in the use of chained field names. A chained field name is a string of field names joined together by periods (' Lets say you wanted to customize your Pedserve installation by adding a new display fields definition for animal search results that shows the animal's name, sex and other fields. You do this by adding a line like this to your setup script:
&pdsSetDisplayFldsDef('A_mydispflds',
'label=My Display Fields;fields1=;fields2=A_NAME,A_SEX,A_DOB,...');
Now lets say that you need to include the names of the sire and dam as columns in the search results. You can't just add in the plain field names - because there are no such fields: the animals table does not have columns for the names of the parents. So, how do you do it? The answer is by using chained field names, chaining through the foreign key fields for the sire and the dam. Like this:
&pdsSetDisplayFldsDef('A_mydispflds',
'label=My Display Fields;fields1=;fields2=A_NAME,A_SEX,A_DOB,A_AID_S.A_NAME,A_AID_D.A_NAME,...');
You can think of Chained field names are not limited to a single 'link'. You can link any number of foreign key fields. E.g. lets say you want to add a new display fields definition for family search results that includes columns for the coat colours of the grandparents. (We are assuming that you have already added a user-defined field for coat colour, called
&pdsSetDisplayFldsDef('F_mydispflds',
'label=With Grandparent Colours;fields1=;fields2='.
'F_AID_S.A_AID_S.A_COLOUR,F_AID_S.A_AID_D.A_COLOUR,'.
'F_AID_D.A_AID_S.A_COLOUR,F_AID_D.A_AID_D.A_COLOUR,...');
... where the term Chained field names can also be used in ordering definitions - so you can order search results according to the values of referenced fields. E.g. a chained field name is used when ordering animal search results by the sire name. Chained field names are also used, implicitly, when you enter search terms e.g. using the advanced search screen. E.g. if you do a search for animals where the name of the sire matches a given pattern, what you are saying to the system is that you want to search a condition that applies to the So, chained field names provide a powerful, generic, way for you to display, order, and select information from the database based on related records from different tables. A Glimpse InsideIf you know anything about SQL databases, you will know that there is no such thing as a chained field name at the SQL level. E.g. you probably know that whilst you can issue a database query like this: SELECT A_NAME FROM GR_A WHERE A_NAME LIKE 'Standfast%' ... you cannot issue a query like this: SELECT A_NAME,A_AID_S.A_NAME FROM GR_A WHERE A_NAME LIKE 'Standfast%' ... because SQL does not know what to do with the SELECT GR_A.A_NAME,T1.A_NAME FROM GR_A LEFT JOIN GR_A AS T1 ON GR_A.A_AID_S=T1.A_ID WHERE GR_A.A_NAME LIKE 'Standfast%' Embedded within the Pedserve system is a database query builder that knows how to handle chained fields occurring in three different places within a database query:
It mechanically constructs the required What this means to you is that users can perform quite complex queries, with results ordered in various ways, bringing together data from multiple tables within a single search results screen - all things that are either not possible, or severely limited, in other, lesser able systems. But it also means that if you have Pedserve Developer Edition, you can easily implement complex database queries. E.g. consider the following Perl code, which manually constructs a query that searches for animals whose name begins with 'Standfast', orders them by descending order of birth date and then by dam name (when the birth dates are the same), fetches the name, birthdate, sire and dam names for the located records, and then outputs them as a table:
# Start by declaring a map that we will build the query in:
my %mQuery = ();
# Initialize the query builder, telling it the table that is
# the 'root' of the query:
&pdsDbQueryBegin(\%mQuery, 'GR_A');
# Add the fields we want returning for the query:
# - name of animal
# - DOB of animal
# - name of sire
# - name of dam
&pdsDbQueryAddApplicationFlds(\%mQuery, 'A_NAME,A_DOB,A_AID_S.A_NAME,A_AID_D.A_NAME');
# Specify the order in which we want the records returned:
# we want them ordered first by descending order of DOB, and
# then by dam name when the DOB is the same:
&pdsDbQueryAddOrderingFlds(\%mQuery, 'A_DOB:desc-1,A_AID_D.A_NAME');
# Add a WHERE clause - we only want to match records where the sire name
# starts with 'Standfast'. This requires that we first 'map' the
# chained field name 'A_AID_S.A_NAME', then add a WHERE term using the
# mapped field:
my $strMappedFld = &pdsDbQueryMapFld(\%mQuery, 'A_AID_S.A_NAME');
&pdsDbQueryAddWhereTerm(\%mQuery, "$strMappedFld LIKE 'Standfast%'");
# Finalize the query: internally this is what builds the SQL etc, but it
# does not execute the query against the database:
&pdsDbQueryFinalize(\%mQuery);
# Now run the query, populating (i) an array @aKeys with the primary keys
# of the matching records (which in this case will be the A_ID values
# because the primary key for the animals table is the A_ID field),
# and (ii) a map %mResults with the field values for each returned record.
my @aKeys = ();
my %mResults = ();
&pdsDbFinalizedQueryRun(\%mQuery, '', \%mResults, \@aKeys);
# The following code just outputs the results returned:
if (!scalar(@aKeys)) {
print $::g_q->p("No results found");
} else {
my $htmlRows = $::g_q->Tr($::g_q->th(['ID', 'Name', 'DOB', 'Sire', 'Dam']))."\n";
for (my $i = 0; $i < scalar(@aKeys); $i++) {
my $id = $aKeys[$i];
my @ahtmlCells = ();
push(@ahtmlCells, $::g_q->escapeHTML($id));
push(@ahtmlCells, $::g_q->escapeHTML($mResults{"$id:A_NAME"}));
push(@ahtmlCells, $::g_q->escapeHTML($mResults{"$id:A_DOB"}));
push(@ahtmlCells, $::g_q->escapeHTML($mResults{"$id:A_AID_S.A_NAME"}));
push(@ahtmlCells, $::g_q->escapeHTML($mResults{"$id:A_AID_D.A_NAME"}));
$htmlRows .= $::g_q->Tr($::g_q->td(\@ahtmlCells))."\n";
}
print $::g_q->table({'-border' => 1}, $htmlRows)."\n";
}
Executing the above code results in a SQL statement along the following lines being created and executed against the database: SELECT GR_A.A_ID,GR_A.A_NAME,GR_A.A_DOB,T1.A_NAME,T2.A_NAME FROM GR_A LEFT JOIN GR_A AS T1 ON GR_A.A_AID_S=T1.A_ID LEFT JOIN GR_A AS T2 ON GR_A.A_AID_D=T2.A_ID WHERE T1.A_NAME LIKE 'Standfast%' ORDER BY IF(GR_A.A_DOB IS NULL,1,0),GR_A.A_DOB DESC,IF(T2.A_NAME IS NULL,1,0),T2.A_NAME When this code is run on the Standfast Golden Retriever Database, the following HTML is generated: <table border="1"><tr><th>ID</th> <th>Name</th> <th>DOB</th> <th>Sire</th> <th>Dam</th></tr> <tr><td>1048984</td> <td>Hayjoy Cola</td> <td>2004-08-06</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Rosie Posy</td></tr> <tr><td>96602</td> <td>Hayjoy Gus</td> <td>2004-08-06</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Rosie Posy</td></tr> <tr><td>1328411</td> <td>Hayjoy Gold Charlie</td> <td>2004-08-06</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Rosie Posy</td></tr> <tr><td>187701</td> <td>Hayjoy Matilda</td> <td>2004-08-06</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Rosie Posy</td></tr> <tr><td>363820</td> <td>Hayjoy Flavia Fleur</td> <td>2003-10-29</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Ellie Precious</td></tr> <tr><td>4564646</td> <td>Hayjoy Sydney</td> <td>2003-10-29</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Ellie Precious</td></tr> <tr><td>3797503</td> <td>Hayjoy Limo</td> <td>2003-10-29</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Ellie Precious</td></tr> <tr><td>3607376</td> <td>Hayjoy Henry in Arden</td> <td>2003-10-29</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Ellie Precious</td></tr> <tr><td>4532723</td> <td>Hayjoy Harvey</td> <td>2003-10-29</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Ellie Precious</td></tr> <tr><td>1136048</td> <td>Hayjoy Popsycle</td> <td>2003-02-28</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Rosie Posy</td></tr> <tr><td>1726073</td> <td>Hayjoy Zoe</td> <td>2003-02-28</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Rosie Posy</td></tr> <tr><td>1580711</td> <td>Hayjoy Barney</td> <td>2003-02-28</td> <td>Standfast Del Rio of Hayjoy</td> <td>Hayjoy Rosie Posy</td></tr> . . . </table> ... which looks something like this when rendered in the user's browser:
Customizing Database TablesThe files |
USEFUL LINKS: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
©1996-2009
Tenset Tech. Ltd
All Rights Reserved