Re: disjoint union types

From: "Ian Barber" <ian(dot)barber(at)gmail(dot)com>
To: pgsql-general(at)postgresql(dot)org
Subject: Re: disjoint union types
Date: 2007-10-10 16:02:36
Message-ID: 3d3003250710100902wbf68e40t1123be3ffcac1949@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

On 10/10/07, Sam Mason <sam(at)samason(dot)me(dot)uk> wrote:
>
> On Tue, Oct 09, 2007 at 10:30:15AM -0500, Erik Jones wrote:
> >On Oct 9, 2007, at 9:38 AM, Sam Mason wrote:
> >> CREATE TABLE circle ( id SERIAL PRIMARY KEY, radius REAL NOT NULL );
> >> CREATE TABLE square ( id SERIAL PRIMARY KEY, sidelen REAL NOT NULL );
> >>
> >> CREATE TABLE shapes (
> >> id SERIAL PRIMARY KEY,
> >>
> >> tag INTEGER NOT NULL,
> >>
> >> circleid INTEGER REFERENCES circle
> >> CHECK ((tag = 1) = (circleid IS NOT NULL)),
> >> squareid INTEGER REFERENCES square
> >> CHECK ((tag = 2) = (squareid IS NOT NULL))
> >> );
> >
> > You could use after triggers on your circle and shape tables to
> > automatically make the insert into shapes for you.
>
> Yes, that helps a bit with getting data in. Doing anything generally
> useful with this data once it's there is still quite painful. If you've
> ever used a language supporting something like this natively then things
> get easier. In, say, Haskell you could do:
>
> data Shape = Circle Double | Square Double
>
> if I then wanted to get the area out I'd be able to do something like:
>
> area (Circle r) = pi * r ^ 2
> area (Square l) = l ^ 2
>
> mapping this over a list is easy. In SQL I'd need to do something much
> more complicated to get the areas of all these shapes out, maybe:
>
> SELECT s.id,
> CASE WHEN s.tag = 1 THEN pi() * r ^ 2
> WHEN s.tag = 2 THEN l ^ 2 END AS area
> FROM shapes s
> LEFT JOIN circle c ON s.tag = 1 AND s.circleid = c.id
> LEFT JOIN square q ON s.tag = 2 AND s.squareid = q.id
>
> This is just a simple example, but if you've got a few of these
> structures to match up it starts to get complicated pretty quickly.
>
>
> Sam
>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: In versions below 8.0, the planner will ignore your desire to
> choose an index scan if your joining column's datatypes do not
> match
>

I wonder if the best way to go would be to use the OO stuff.

If you had a "shapes" table, that had the various operations you were
interested in (say area), then you could have a circle table inherit from
that, and automatically compute the area with a trigger, as Erik suggested.
Then you could just query shapes:

CREATE TABLE shapes (
shape_id serial PRIMARY KEY,
area real not null
);

CREATE TABLE circle (
radius real not null
) INHERITS (shapes);

CREATE FUNCTION circle_area() RETURNS trigger AS $circle_area$
BEGIN
NEW.area = pi() * NEW.radius ^ 2;
RETURN NEW;
END;
$circle_area$ LANGUAGE plpgsql;

CREATE TRIGGER circle_area BEFORE INSERT OR UPDATE ON circle
FOR EACH ROW EXECUTE PROCEDURE circle_area();

INSERT INTO circle (radius) values (5)
SELECT * FROM shapes

shape_id 1
area 78.5398

Ian Barber

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Henrik 2007-10-10 16:02:51 Disable triggers per transaction 8.2.3
Previous Message Dmitry Koterov 2007-10-10 15:26:15 Re: How to speedup intarray aggregate function?