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
>

Reply via email to