Thread: Indirect access to data, given table name as a string

Indirect access to data, given table name as a string

From
Arthaey Angosii
Date:
I want to allow "notes" on any row in any table in my database. A
table row may have multiple notes. Say my tables are "foo," "bar," and
"qux." I want to avoid having a lookup table for each of them
("foo_notes," "bar_notes," and "qux_notes").

Is there a standard way of solving this problem?

Not knowing SQL all that well, I thought that maybe I could have a
"notes" table:

CREATE TABLE notes (
    id integer primary key,
    table_name regclass not null,
    row_id integer not null,
    note text not null
);

But I have no idea how I could use notes.table_name and notes.row_id
to relate (table_name.id = row_id) to notes.note. I've looked a little
bit at information_schema and the system catalog, but I haven't found
any examples of what I'm trying to do, so I don't know if I'm on the
right track here.

Any suggestions would be appreciated!


Re: Indirect access to data, given table name as a string

From
Ron Johnson
Date:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 04/21/07 20:31, Arthaey Angosii wrote:
> I want to allow "notes" on any row in any table in my database. A
> table row may have multiple notes. Say my tables are "foo," "bar," and
> "qux." I want to avoid having a lookup table for each of them
> ("foo_notes," "bar_notes," and "qux_notes").
>
> Is there a standard way of solving this problem?
>
> Not knowing SQL all that well, I thought that maybe I could have a
> "notes" table:
>
> CREATE TABLE notes (
>     id integer primary key,
>     table_name regclass not null,
>     row_id integer not null,
>     note text not null
> );
>
> But I have no idea how I could use notes.table_name and notes.row_id
> to relate (table_name.id = row_id) to notes.note. I've looked a little
> bit at information_schema and the system catalog, but I haven't found
> any examples of what I'm trying to do, so I don't know if I'm on the
> right track here.
>
> Any suggestions would be appreciated!

For this kind of scheme, add a "note_id integer" to each relevant
"main" table, and then have your notes table look like this:

CREATE TABLE notes (
    id integer,
    row_id smallint not null,
    note text not null,
    primary key (id, row_id)
);

You'll also need an "id_master" table to keep track of the next id.
 (A serial datatype would not work because the PK is compound.)

This makes sense to me.  I hope I was able to elucidate it clearly.

- --
Ron Johnson, Jr.
Jefferson LA  USA

Give a man a fish, and he eats for a day.
Hit him with a fish, and he goes away for good!

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQFGLMmAS9HxQb37XmcRAgMLAKCgc/bEq8GlqZPeGooeRopxLcilQACfalUb
mUV+4cZ3lv6Bas5KGuoKLUE=
=MEQY
-----END PGP SIGNATURE-----

Re: Indirect access to data, given table name as a string

From
David Lee Lambert
Date:
On Sat, 2007-04-21 at 18:31 -0700, Arthaey Angosii wrote:
> I want to allow "notes" on any row in any table in my database. A
> table row may have multiple notes. Say my tables are "foo," "bar," and
> "qux." I want to avoid having a lookup table for each of them
> ("foo_notes," "bar_notes," and "qux_notes").
>
> Is there a standard way of solving this problem?
>
> Not knowing SQL all that well, I thought that maybe I could have a
> "notes" table: [...]
> But I have no idea how I could use notes.table_name and notes.row_id
> to relate (table_name.id = row_id) to notes.note.

You can save some space by referring to the table by its OID:

CREATE TABLE notes (
  id SERIAL,
  table_id OID,
  row_id BIGINT,
  note VARCHAR NOT NULL,
  PRIMARY KEY(id) );
CREATE INDEX notes_table_row_idx ON notes (table_id,row_id);

You could even write one query to get some data and the notes from all
tables:

 SELECT 'Bar',tableoid,oid,NULL,x,y FROM bar
UNION ALL
 SELECT 'Foo',tableoid,oid,name,NULL,NULL FROM foo;

However,  if you want to do what you're asking about,  you're probably
working in some object-oriented framework.  You might have queries that
look like:

SELECT x,y FROM bar WHERE id=?

This would change to

SELECT x,y FROM bar WHERE id=?  -- returns 1 row, if id is valid
SELECT note FROM bar
  LEFT OUTER JOIN notes
  ON bar.tableoid=notes.table_id AND bar.id=notes.row_id
  WHERE id=?  -- returns 0..* rows

It might be easier to create a base-class that includes your preferred
ID generation logic,  the "note" column (possibly just a nullable id for
the seperate "notes" table), any any other application-wide columns
(responsible user, modification date...) that you want to use.  You
could even use Postgres inheritance for that base table,  although you
wouldn't have to.

One last question:  do you want notes on the "notes" table itself, if
you create one?