There is probably a way to get this done, but are you sure this is what you want to do? This structure could be difficult to work with if you need to look stuff up. If your purpose is more informational than analytical, it might work. A query that selects all systems with a particular version, installation date and path could be difficult to write with your given structure.
It all depends on what you're trying to get done, but here's how it looks to me. Your swconfig_names table looks more like column names for either your system table or your swconfig_name_val_xref table. This depends on whether you will store multiple sw config's for each system.
Your swconfig_values table looks like it should be three tables. Rather than one table that serves 3 purposes, you might consider three tables, each with a single purpose--controlling the input of a single column value. As I recall, part of normalization is that each column has one and only one definition.
Here's how I see it organized:
Drop swconfig_names.
Create 4 tables consisting of an id and a value:
sw_path (path_id, value),
sw_version (version_id, value),
sw_date_installed (installed_id, value),
sw_system (system_id, value)
Now create table sw_config with 5 columns:
config_id, path_id, version_id, installed_id, system_id
At this point each column in sw_config has one and only one definition, and it will be easier to analyze and manipulate the data. This has a minimum one row to insert into one table. The structure you outlined above would require a minimum of three rows to insert to track the same data.
This looks like it might work if you have only one software package to track. If you have multiple packages and versions, the structure begins to break down.
There are lots of ways to take care of validating values. What works best for you depends on how you are getting the data. If the data is form generated, you have control over what is entered to a certain extent. You give the user choices from the list of possible values, or allow the user to add a new value. Have your form return either the id of the existing option or the text of the new value. If you get an id you don't need to validate it. If you get text, you will add it to the appropriate lookup table, get the new id back, then add it to sw_config.
If you're getting the data as a list of values (not codes) it's a bit different. Then you would need to lookup the text entry to get an id, or add a new code. If you load each of the lookup tables into a hash (value, id) you can save a lot of time doing lookups. Look for an id for your value using the exists function. If the value exists, use the id to update sw_config. If not, add the new value to the lookup table and reload the hash. Something like this:
%sw_path = &load_hash('sw_path','value','path_id') ;
$value_to_save = &get_value('path') ;
if (exists $sw_path{$value_to_save) {
$path_id = $sw_path{$value_to_save);
}
else {
$path_id = &insert_row('sw_path',$value_to_save) ;
%sw_path = &load_hash('sw_path','value','path_id') ;
}
Do this for each of the codified columns in preparation for the insert/update into sw_config. Functions &load_hash, &get_value and &insert_row are user-defined (the user would be you) in Perl. I'm sure you can figure that out.
But this will only work 100% of the time if only one copy of the import program is running at a time. If a second copy is running you could wind up with multiple rows having the same value. It all depends mostly on the particulars of your application, and somewhat on your personal style and preferences.