Hi Alex Another option: replace `(navigation.target_type, navigation.target_id)` with `(navigation.html_target_id, navigation.fancyscript_target_id)` only one of which is defined for any given row, but both of which have foreign key constraints when they are defined.
In answer to a subset of your questions: > Is there a standard approach for this kind of database table construct? Not that I'm aware of. > Is there a best practice? I think this discussion responds to that question. http://dba.stackexchange.com/questions/15388/where-should-you-define-foreign-keys As you'll see from the responses, the context of an application has a major influence on the decision made. I hope that helps! Andrew On Sat, Apr 11, 2015 at 8:17 AM, Tommi Helander <tommi.helan...@outlook.com> wrote: > Hi Alex, > > Without going into details about your data model in general, then in your > case I would probably create two different navigation tables: one for html > and one for scripts. Then I would be able to create reliable foreign key > constraints. Then, if I wanted a convenient way of selecting all kinds of > navigation records from Perl, I would create a view that combines the > different kinds of navigation tables and contain the kind of type field and > id field that you suggested. You see, this would make it possible to assign > constraints on the underlying data model, without complicating the way it's > selected. > > On the other hand, I usually work with larger databases and more complex > data models, so this might be a little overkill in your case. But anyway, > this what I consider good practice. Others may have different opinions. > > Hope this helps! > > Best regards, > Tommi > ------------------------------ > Från: Alex Becker <asb.c...@gmail.com> > Skickat: 10.4.2015 23:56 > Till: Andrew Solomon <and...@geekuni.com> > Kopia: beginners@perl.org > Ämne: Re: Inhomogeneous data in a database > > Hi Andrew, > > I'm not interested in ways how to get the data out of the database. I'm > usually using DBIx::CLass because I'm too lazy to write SQL. > > To provide you an example of a table and the question I have, I did it > anyway :). This would be the example case: > > #!perl > > use strict; > use warnings; > use DBI; > use DBD::SQLite; > > my $db_file = 'test.sqlite'; > unlink $db_file if -e $db_file; > > my $dbh = DBI->connect("dbi:SQLite:dbname=$db_file", '', '') or die("Could > not connect to database $db_file"); > > my @stmts = ( > q~CREATE TABLE "html_contents" ( > "content_id" INTEGER PRIMARY KEY NOT NULL, > "title" varchar(255) NOT NULL, > "html" TEXT NOT NULL > );~, > q~CREATE TABLE "fancy_scripts" ( > "script_id" INTEGER PRIMARY KEY NOT NULL, > "perl_module" varchar(255) NOT NULL > );~, > q~CREATE TABLE "navigation" ( > "navigation_id" INTEGER PRIMARY KEY NOT NULL, > "position" INTEGER UNIQUE NOT NULL, > "link_text" carchar(45) NOT NULL, > "target_type" varchar(45) NOT NULL, > "target_id" INT NOT NULL > );~, > q~INSERT INTO html_contents VALUES (1, "Title1", > "<html><body><h1>Start Page</h1></body></html>")~, > q~INSERT INTO html_contents VALUES (2, "Title n", > "<html><body><h1>This is Mario!</h1></body></html>")~, > q~INSERT INTO fancy_scripts VALUES (1, "CMS::FancyScript")~, > q~INSERT INTO fancy_scripts VALUES (2, "CMS::Guestbook")~, > q~INSERT INTO navigation VALUES (1, 1, "Home", "html_contents", 1)~, > q~INSERT INTO navigation VALUES (2, 3, "About Me", "html_contents", > 2)~, > q~INSERT INTO navigation VALUES (3, 2, "Contact", "fancy_scripts", 1)~, > ); > > foreach my $sql ( @stmts ) { > $dbh->do($sql) or die("Something bad happened doing SQL: " . > $dbh->errstr); > } > > print "> done\n"; > exit(0); > > > The issue is: > Usually, when reading articles about database normalization, everyone > talks about putting information into separate tables and referencing them > (e.g. using foreign keys). > I did so. Every information has a dedicated table (except for the > target_type column for the sake of example simplicity). > > But the value of the target_id column cannot be defined as a foreign key. > Because it might be an ID of the table fancy_scripts or one of the table > "html_contents". I know which table to use depending on the value of > target_type. > > I even could create 2 views to denormalize the tables for fast access. One > view would reflect the navigation links for fancy scripts, and one would > reflect the navigation links for html contents. > > But: usually, when fetching a navigation structure of some kind, you fetch > *all* the links. > > It can be done. I can code it the way I want it to work. > But I'm *not sure* if it is the right thing to do (and no, I don't really > want to start a discussion about TIMTOWTDI, Perl's philosophy, why Pyhton > wuld be better for this approach, or what people think about this > particular sentence in general). > > Maybe I can rephrase my inital questions: > > > Is there a standard approach for this kind of database table construct? > Is it the right thing to do? > > > A coding recommendation? > Is there a best practice? > > > Or am I doing it completely wrong? > Should I store the information in another fashion? > > Thanks for your answers & best regards, > Alex > > 2015-04-10 21:51 GMT+02:00 Andrew Solomon <and...@geekuni.com>: > > Hi Alex > > Maybe you could give us a bit more info on the `html_contents` and > `fancy_scripts` tables, because my inclination would be just to have a > simple `contents` table. > > This table would have three fields: (`id,`content_type`, `blob`) where: > * `content_type` is "HTML", "CGI" or "Module" (or rather, ids pointing to > the `target_type` table); > * `blob` is a base64 encoding of a structure containing both the data > (HTML, CGI or module) and any metadata such as URL parameters, class > attributes etc. > > I would then be using DBIx::Class to access the table and have methods > on the Schema to decode and make use of `blob` appropriately depending on > the `content_type`. > > Perhaps it would be easier to have two fields (`metadata`, `data`) > instead of `blob` but you get the idea. > > Let me know if that's clear as mud, or I've missed the point altogether:) > > Andrew > > > > On Fri, Apr 10, 2015 at 6:04 PM, Alex Becker <asb.c...@gmail.com> wrote: > > Hi! > > This is not directly a Perl question, but since Perl is the only language > I code in, I hope you could help me out. > > I have a database for a very simple Perl-based Web CMS. > The CMS knows only 2 types of content: a HTML web site or a Perl module > executing some fancy CGI script. > > So let's assume I have 3 tables: > a) html_contents > b) fancy_scripts > c) navigation > > HTML contents is trivial. It's an excel-sheet-like table with a title > and the HTML code. > > Fancy scripts work the same, except that it's maybe the URL to the CGI > script, or a class name. > > Navigation however can hold 2 kinds of content: a reference to a row in > the HTML contents table or a reference to one of those fancy scripts. > > How do I do that? > My current approach is the following: > > Make the navigation table have 3 columns: > <id, target_type, target_id> > > target_type is an identifier for the kind of thing I reference. In the > example, it could be fancy_script or content. > > But now I get a bad feeling because I can't really make the column > target_it a foreign key that really is a reference to one of those tables > (scripts or HTML). > I usually always do it that way. I even normalize the target_type so > that I have an extra table for target_types with a target type ID and an > ident. > > Is there a standard approach for this kind of database table construct? > A coding recommendation? > Or am I doing it completely wrong? > > Best regards, > Alex > > > > > -- > Andrew Solomon > > Mentor@Geekuni http://geekuni.com/ > http://www.linkedin.com/in/asolomon > > > -- Andrew Solomon Mentor@Geekuni http://geekuni.com/ http://www.linkedin.com/in/asolomon