| Naming Database Tables, Columns and Indexes |
| Table names |
| Column names |
| Column names used in searches |
| Index names |
| Handling Yes/No type columns |
| Sample Code |
| Q and A |
| Naming Names |
| Resources |
| Author |
| Licence |
Naming Database Tables, Columns and IndexesThis article discusses my ideal naming scheme for these items. By ideal I mean that it is:
Table namesTable names obey the following rules:
Column namesTable names obey the following rules:
Also, when using rules like these to name columns, graphing database schema becomes easier. Why? Because to draw lines between boxes which represent tables, the code must be able to report which tables contain foreign keys. This can be done in various ways, but as always, the simpler the better. Column names used in searchesWhen a column is to be used as the subject of a search, I create 2 parallel columns, one containing the real data, and one containing a lower case version of the data. The two columns have the same name, but with the latter column's name also having the suffix _key. Hence, in the person table I'd have person_name and person_name_key. Note: some databases, eg MySQL, by default perform case-insensitive matches on text columns. What I'm suggesting here is a policy, or strategy if you will, on what to do when MySQL is not the platform at hand. Index namesI've adopted the mindlessly simple method of using the column name as the prefix of the index name, only where (of course) the index is just on one column. There is some sample code below, but to repeat it here: Column name: service_class_name_key Index name: service_class_name_key_index The component _key is explained in the previous section. Handling Yes/No type columnsNothing special is required here. Let's say we have a company table. Then to record the fact some companies might wish to opt out of a survey, we would have a column called company_opt_out. We can make several observations about this column name:
Let's take another example: Private (silent) phone numbers. Actually they do ring, so they are not silent.... The column in the service table would be called service_is_silent, and the Perl code is: if ($$data{'service_is_silent'} eq 'Yes')
{
:
}
Sample CodeSince TMTOWTDI, here's another way: In our class's constructor, we create an instance of DBIx::SQLEngine: $$self{'_sql_engine'} = DBIx::SQLEngine -> new
(
'DBI:mysql:db_name:127.0.0.1', 'db_user', 'db_pass',
{
AutoCommit => 1,
PrintError => 0,
RaiseError => 1,
ShowErrorStatement => 1,
}
);
Here are some comments from the DBIx::SQLEngine docs:
Interestingly, in /perl/site/lib/DBIx/SQLEngine/ you'll find SQLite.pm. Now we create a table: my($table_name) = 'service_class';
my($column) =
[
{
name => 'service_class_id',
type => 'sequential',
},
{
name => 'service_class_code',
type => 'char(5)',
},
{ # This holds lc service_class_code.
name => 'service_class_code_key',
type => 'char(5)',
},
{
name => 'service_class_name',
type => 'text',
},
{ # This holds lc service_class_name.
name => 'service_class_name_key',
type => 'text',
},
];
$self -> do_drop_table($table_name); $self -> do_create_table($table_name, $column); $self -> do_create_index($table_name, 'service_class_code_key'); $self -> do_create_index($table_name, 'service_class_name_key', 'unique'); Here's what the last 3 methods look like: sub do_drop_table
{
my($self, $table_name) = @_;
my(@column) = $$self{'_sql_engine'} -> detect_table($table_name, 1);
$$self{'_sql_engine'} -> do_drop_table($table_name) if ($#column >= 0);
} # End of do_drop_table. sub do_create_table
{
my($self, $table_name, $column) = @_;
$$self{'_sql_engine'} -> do_create_table($table_name, $column);
} # End of do_create_table. sub do_create_index
{
my($self, $table_name, $index_column, $unique) = @_;
$unique ||= '';
my($sql) = "create $unique index ${index_column}_index " .
"on $table_name ($index_column)";
$$self{'_sql_engine'} -> do_sql($sql);
} # End of do_create_index. We can make a few observation on this code:
Q and AQ: So why put the table name on the column name in the first place? A: Because site_id and building_id are unique, whereas to call them both id adds complexity for little gain, and having id in every table means every SQL statement containing a join has to have dis-ambiguation code added. Q: But doesn't this convention mean extra typing? A: Yes, but that's why I wrote the CGI form generator :-). E.g.: building_site_id (in the building table). The column name is building_site_id, and site_id is readily found to be the name of a column, hence building_site_id is necessarily a foreign key. My package, like others (using perhaps different methods), can then automatically determine database joins by this consistent naming of foreign keys. This in turn means CGI forms containing drop-down menus can be automatically constructed from foreign keys. E.g.: If we have a table called person_title, with a primary key person_title_id, then in the person table, the foreign key into the person_title table will be called person_person_title_id. This may look odd at first, but the convenience of always knowing exactly what's where rapidy becomes a habit. The algorithm given above for converting a column name into a prompt means person_person_title_id is displayed neatly as 'Person title', the table name prefix person_ and the _id suffix having been dropped. Not only that, but when displaying data for one person, or when displaying an empty input screen, we can automatically populate the title field with a pop-up menu taken directly from the person_title table. Naming NamesWherever plausible, I have a column in each table called 'table name'_name, to be used by display programs. In the case of a table called person, there would columns like person_given_names, person_initials and person_surname, so person_name would be populated whenever a new record was added, by person_given_names + '1 space' + person_surname, or if there was a column called person_preferred_name, then by person_preferred_name + '1 space' + person_surname. By default, the auto-generation of pop-up menus just mentioned would use such a column for display, and use the corresponding value of the primary key as the value to associate to the visible string. Lastly, I say 'Wherever plausible', since in cases like a table of phone services, 'name' is just not appropriate. ResourcesAn image of such a schema as described above: http://savage.net.au/assets/images/web-site/aussi.png. The process of installing the software to create this image is documented here: http://savage.net.au/Ron/html/graphing-database-schema.html. Other database drawing tools: http://savage.net.au/Ron/html/drawing-tools.html. AuthorRon Savage Home page: http://savage.net.au/index.html This POD was converted to HTML by /Perl.html#fancy-pom2.pl
LicenceAustralian Copyright © 2002 Ron Savage. All rights reserved. All Programs of mine are 'OSI Certified Open Source Software'; you can redistribute them and/or modify them under the terms of The Artistic License, a copy of which is available at: http://www.opensource.org/licenses/index.html |
| Top of page |