HiveBrain v1.2.0
Get Started
← Back to all entries
patternsqlMinor

Schema for allowing adding tags to entities in unrelated tables

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
allowingtablesunrelatedaddingtagsforentitiesschema

Problem

I'm implementing a "tags" features to an already working solution.

Final users need to be able to add tags to three separate sections of the solution:

  • Posts



  • Accounts



  • Groups



Each section has its corresponding table in the database, and each table contains a unique ID:

  • PostID



  • AccountID



  • GroupID



I'm thinking about implementing a tag schema similar to the one that Wordpress uses, where I'll have:

  • A tagmap table that will contain a unique ID for each "tagmap".



  • A foreign key to each section's table ID.



  • Another foreign key to the ID of the tag.



CREATE TABLE Posts(
  PostID int(2) NOT NULL AUTO_INCREMENT,
  Content varchar(255),
  PRIMARY KEY(PostID)
 );

CREATE TABLE Groups(
  GroupID int(2) NOT NULL AUTO_INCREMENT,
  GroupName varchar(255),
  PRIMARY KEY(GroupID)
 );

CREATE TABLE Links(
  LinkID int(2) NOT NULL AUTO_INCREMENT,
  href varchar(255),
  PRIMARY KEY(LinkID)
 );

CREATE TABLE tagmap(
  TagmapID int(2) NOT NULL AUTO_INCREMENT,
  PostID int(2),
  GroupID int(2),
  LinkID int(2),
  TagID int(2) NOT NULL,
  PRIMARY KEY(TagmapID)
 );

CREATE TABLE tags(
  TagID int(2) NOT NULL AUTO_INCREMENT,
  TagName varchar(255) NOT NULL,
  PRIMARY KEY(TagID)
);


I like this approach because it is decently normalized, but queries might get a bit complex. Also, it will have a lot of NULL columns every time a tag is assigned to a post but not to an account or to a group, so I'm unsure how it will behave performance-wise (the table will hold around 100,000 records almost immediately).

Is there a better alternative to this?

Solution

A simple solution is to include a table reference in the tagmap instead of many id columns.

CREATE TABLE tagmap(
  TagmapID int(2) NOT NULL AUTO_INCREMENT,
  RefTable varchar(255) NOT NULL,
  RefID int(2),
  TagID int(2) NOT NULL,
  PRIMARY KEY(TagmapID),
  INDEX(RefTable, RefID),
  UNIQUE(RefTable, RefID, TagID)
);


With that approach, you can easily make other tables taggable. To retrieve the tags for a post, you'd just say

SELECT TagName FROM tags
LEFT JOIN tagmap USING TagID
WHERE RefTable = 'posts' AND RefID = 42

Code Snippets

CREATE TABLE tagmap(
  TagmapID int(2) NOT NULL AUTO_INCREMENT,
  RefTable varchar(255) NOT NULL,
  RefID int(2),
  TagID int(2) NOT NULL,
  PRIMARY KEY(TagmapID),
  INDEX(RefTable, RefID),
  UNIQUE(RefTable, RefID, TagID)
);
SELECT TagName FROM tags
LEFT JOIN tagmap USING TagID
WHERE RefTable = 'posts' AND RefID = 42

Context

StackExchange Code Review Q#26828, answer score: 3

Revisions (0)

No revisions yet.