このブログ投稿がおもしろいと思います:タグ:データベーススキーマ
問題:ブックマーク(またはブログ投稿など)に必要な数のタグを付けることができるデータベーススキーマが必要です。その後、クエリを実行して、ブックマークをタグの和集合または共通部分に制限します。また、検索結果から一部のタグを除外する(たとえば、マイナスにする)必要があります。
「MySQLicious」ソリューション
このソリューションでは、スキーマにテーブルが1つだけあり、非正規化されています。このタイプは、MySQLiciousがdel.icio.usデータをこの構造のテーブルにインポートするため、「MySQLiciousソリューション」と呼ばれます。
「search + webservice + semweb」の交差(AND)クエリ:
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags LIKE "%semweb%"
「search | webservice | semweb」のユニオン(OR)クエリ:
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
OR tags LIKE "%webservice%"
OR tags LIKE "%semweb%"
「search + webservice-semweb」のマイナスクエリ
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags NOT LIKE "%semweb%"
「Scuttle」ソリューション
Scuttleは、データを2つのテーブルに整理します。そのテーブル「scCategories」は「タグ」テーブルであり、「ブックマーク」テーブルへの外部キーを持っています。
「bookmark + webservice + semweb」の交差点(AND)クエリ:
SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
HAVING COUNT( b.bId )=3
最初に、すべてのブックマークとタグの組み合わせが検索されます。タグは「bookmark」、「webservice」、または「semweb」(c.category IN( 'bookmark'、 'webservice'、 'semweb'))であり、次にそのブックマークのみが検索されます。検索された3つのタグすべてが考慮されます(HAVING COUNT(b.bId)= 3)。
「bookmark | webservice | semweb」のユニオン(OR)クエリ:
HAVING句を省略するだけで、ユニオンができます。
SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
マイナス(除外)「bookmark + webservice-semweb」のクエリ。つまり、ブックマークとWebサービスであり、semwebではありません。
SELECT b. *
FROM scBookmarks b, scCategories c
WHERE b.bId = c.bId
AND (c.category IN ('bookmark', 'webservice'))
AND b.bId NOT
IN (SELECT b.bId FROM scBookmarks b, scCategories c WHERE b.bId = c.bId AND c.category = 'semweb')
GROUP BY b.bId
HAVING COUNT( b.bId ) =2
HAVING COUNTを省略すると、「bookmark | webservice-semweb」のクエリが表示されます。
「Toxi」ソリューション
Toxiは3つのテーブル構造を考え出しました。テーブル「タグマップ」を介して、ブックマークとタグはn-to-mに関連しています。各タグは、異なるブックマークと一緒に使用でき、その逆も可能です。このDBスキーマはwordpressでも使用されます。クエリは「scuttle」ソリューションの場合とまったく同じです。
「bookmark + webservice + semweb」の交差点(AND)クエリ
SELECT b.*
FROM tagmap bt, bookmark b, tag t
WHERE bt.tag_id = t.tag_id
AND (t.name IN ('bookmark', 'webservice', 'semweb'))
AND b.id = bt.bookmark_id
GROUP BY b.id
HAVING COUNT( b.id )=3
Union(OR)「bookmark | webservice | semweb」のクエリ
SELECT b.*
FROM tagmap bt, bookmark b, tag t
WHERE bt.tag_id = t.tag_id
AND (t.name IN ('bookmark', 'webservice', 'semweb'))
AND b.id = bt.bookmark_id
GROUP BY b.id
マイナス(除外)「bookmark + webservice-semweb」のクエリ。つまり、ブックマークとWebサービスであり、semwebではありません。
SELECT b. *
FROM bookmark b, tagmap bt, tag t
WHERE b.id = bt.bookmark_id
AND bt.tag_id = t.tag_id
AND (t.name IN ('Programming', 'Algorithms'))
AND b.id NOT IN (SELECT b.id FROM bookmark b, tagmap bt, tag t WHERE b.id = bt.bookmark_id AND bt.tag_id = t.tag_id AND t.name = 'Python')
GROUP BY b.id
HAVING COUNT( b.id ) =2
HAVING COUNTを省略すると、「bookmark | webservice-semweb」のクエリが表示されます。