On Fri, Jul 24, 2009 at 09:20:29PM -0500, P Kishor scratched on the wall:
> I am trying to develop a "tagging" system, whereby each row in a table
> can be tagged with arbitrary number of tags.

  This smells of a Relational division problem.  If you're dealing with
  tags you might want to have a look at that (Celko has a few good
  articles on it).  Since SQL lacks a native Relational division
  operator, chances are a solution in that direction is going to be
  more complex -- at least for this problem.  But any time I've done
  tags or attributes, sooner or later I find myself needing to do a
  division.  They come in handy any time you say "my data is vertical
  but I need it horizontal."  You might want to read up on them just to
  have that knowledge available.


> TABLE foo (f_id INTEGER PRIMARY KEY, f_name TEXT);
> TABLE tag (t_id INTEGER PRIMARY KEY, t_name TEXT);
> TABLE foo_tag (f_id INTEGER, t_id INTEGER);


> I have the following solution. Could I do better or differently?

  I'm not sure about "better", but here's different:

sqlite> SELECT foo.f_name, tag.t_name 
   ...> FROM tag AS target 
   ...>   NATURAL JOIN foo_tag AS target_ft
   ...>   NATURAL JOIN foo
   ...>   NATURAL JOIN foo_tag
   ...>   NATURAL JOIN tag
   ...> WHERE target.t_name = 'bar' 
   ...>   AND tag.t_id != target.t_id
   ...> ORDER BY foo.f_name, tag.t_name;

  This basically folds your IN sub-select back into the main query.
  We join "foo" to the tag table in two directions... one to find
  the search target tag id and the other to produce the output.

  "tag AS target" with the first WHERE clause should return one row.
  We join that through "foo_tag AS target_ft" to get a list of foo ids
  that have the search target tag.  We then build the normal output
  list by joining that back through the foo_tag bridge table to the
  tags, and throw out any rows with an output tag id that matches the
  search target tag id.

  Simple!

  Best of all, the target only appears in the query once, and your name
  convention means we can use NATURAL JOINs to keep things clean.  It
  also totally falls apart if you need to search on more than one tag.
  That's where Relational division comes in.

   -j (who had to draw a picture to get it right)

-- 
Jay A. Kreibich < J A Y  @  K R E I B I.C H >

"Our opponent is an alien starship packed with atomic bombs.  We have
 a protractor."   "I'll go home and see if I can scrounge up a ruler
 and a piece of string."  --from Anathem by Neal Stephenson
_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to