web-dev-qa-db-ja.com

SQL Serverの多対多の関係、行の再利用?

以下は、典型的な多対多の関係です。まったく同じタグを持つ2つのタスクがあるとします。外部キーと主キーの関係の制約のため、テーブルTasksTagの行を再利用する方法はありません(両方のタスクのPKが同じになる;不可能)

私のシナリオでは、理論的には、タスクには通常ほとんどまたはすべてのタグが含まれます。つまり、すべてのタスクのTasksTagテーブルには約300行以上あります。 1か月に数百のタスクがあり、その多くは同じタグリストを持つため、これはひどくスケーリングします。

誰かが制約を削除せずにこれを行う別の方法を説明できますか?スペースが気になりますか?

ありがとう!

enter image description here

2
ryand

以下のサンプル構造は、TasksTagsテーブルを最も効率的に実行する方法を示しています。 Tasksテーブルは、一意のタスク名を適用します。タグテーブルは、一意のタグ名を適用します。 TasksTagsテーブルはこれらを結合し、タスクとタグの任意の組み合わせを可能にします。

USE tempdb;
CREATE TABLE dbo.Tasks
(
    TaskID INT NOT NULL CONSTRAINT PK_Tasks PRIMARY KEY CLUSTERED IDENTITY(1,1)
    , TaskName VARCHAR(255) NOT NULL CONSTRAINT UQ_Tasks_TaskName UNIQUE
);
CREATE TABLE dbo.Tags
(
    TagID INT NOT NULL CONSTRAINT PK_Tags PRIMARY KEY CLUSTERED IDENTITY(1,1)
    , TagName VARCHAR(255) NOT NULL CONSTRAINT UQ_Tags_TagName UNIQUE
);
CREATE TABLE dbo.TasksTags
(
    TaskID INT NOT NULL
    , TagID INT NOT NULL
    , CONSTRAINT PK_TasksTags PRIMARY KEY CLUSTERED (TaskID, TagID)
);
INSERT INTO dbo.Tasks (TaskName) VALUES ('Task1');
INSERT INTO dbo.Tasks (TaskName) VALUES ('Task2');
INSERT INTO dbo.Tasks (TaskName) VALUES ('Task3');

INSERT INTO dbo.Tags (TagName) VALUES ('MyTag1');
INSERT INTO dbo.Tags (TagName) VALUES ('MyTag2');
INSERT INTO dbo.Tags (TagName) VALUES ('MyTag3');

INSERT INTO dbo.TasksTags (TaskID, TagID) VALUES (1,2);
INSERT INTO dbo.TasksTags (TaskID, TagID) VALUES (1,3);
INSERT INTO dbo.TasksTags (TaskID, TagID) VALUES (1,1);
INSERT INTO dbo.TasksTags (TaskID, TagID) VALUES (2,2);
INSERT INTO dbo.TasksTags (TaskID, TagID) VALUES (2,3);
INSERT INTO dbo.TasksTags (TaskID, TagID) VALUES (3,2);
INSERT INTO dbo.TasksTags (TaskID, TagID) VALUES (3,1);


SELECT TK.TaskName, TG.TagName
FROM dbo.TasksTags TT
    INNER JOIN dbo.Tasks TK ON TT.TaskID = TK.TaskID
    INNER JOIN dbo.Tags TG ON TG.TagID = TT.TagID;

enter image description here

[〜#〜]編集[〜#〜]

以下では、タグのリストを複数のタスクに関連付けることができます。これを以前の構造とブレンドして、各タスクのタグの完全にカスタマイズ可能なリストを作成できます。

USE tempdb;
CREATE TABLE dbo.Tasks
(
    TaskID INT NOT NULL CONSTRAINT PK_Tasks PRIMARY KEY CLUSTERED IDENTITY(1,1)
    , TaskName VARCHAR(255) NOT NULL CONSTRAINT UQ_Tasks_TaskName UNIQUE
);
CREATE TABLE dbo.Tags
(
    TagID INT NOT NULL CONSTRAINT PK_Tags PRIMARY KEY CLUSTERED IDENTITY(1,1)
    , TagName VARCHAR(255) NOT NULL CONSTRAINT UQ_Tags_TagName UNIQUE
);
CREATE TABLE dbo.TagList
(
    TagListID INT NOT NULL CONSTRAINT PK_TagList PRIMARY KEY CLUSTERED IDENTITY(1,1)
    , TagListName VARCHAR(255) NOT NULL CONSTRAINT UQ_TagList_Name UNIQUE
);
CREATE TABLE dbo.TagListTags
(
    TagListID INT NOT NULL CONSTRAINT FK_TagListTags_TagListID FOREIGN KEY REFERENCES dbo.TagList(TagListID)
    , TagID INT NOT NULL CONSTRAINT FK_TagListTags_TagID FOREIGN KEY REFERENCES dbo.Tags(TagID)
    , CONSTRAINT PK_TasksTags PRIMARY KEY CLUSTERED (TagListID, TagID)
);
CREATE TABLE dbo.TasksTagList
(
    TaskID INT NOT NULL CONSTRAINT FK_TasksTagList_TaskID FOREIGN KEY REFERENCES dbo.Tasks(TaskID)
    , TagListID INT NOT NULL CONSTRAINT FK_TasksTagList_TagListID FOREIGN KEY REFERENCES dbo.TagList(TagListID)
    , CONSTRAINT PK_TasksTagList PRIMARY KEY CLUSTERED (TaskID, TagListID)
);


INSERT INTO dbo.Tasks (TaskName) VALUES ('Task1');
INSERT INTO dbo.Tasks (TaskName) VALUES ('Task2');
INSERT INTO dbo.Tasks (TaskName) VALUES ('Task3');

INSERT INTO dbo.Tags (TagName) VALUES ('MyTag1');
INSERT INTO dbo.Tags (TagName) VALUES ('MyTag2');
INSERT INTO dbo.Tags (TagName) VALUES ('MyTag3');

INSERT INTO dbo.TagList (TagListName) VALUES ('Tag List 1');
INSERT INTO dbo.TagList (TagListName) VALUES ('Tag List 2');

INSERT INTO dbo.TagListTags (TagListID, TagID) VALUES (1, 1);
INSERT INTO dbo.TagListTags (TagListID, TagID) VALUES (1, 2);
INSERT INTO dbo.TagListTags (TagListID, TagID) VALUES (1, 3);
INSERT INTO dbo.TagListTags (TagListID, TagID) VALUES (2, 1);
INSERT INTO dbo.TagListTags (TagListID, TagID) VALUES (2, 3);

INSERT INTO dbo.TasksTagList (TaskID, TagListID) VALUES (1, 1);
INSERT INTO dbo.TasksTagList (TaskID, TagListID) VALUES (2, 1);
INSERT INTO dbo.TasksTagList (TaskID, TagListID) VALUES (2, 2);


SELECT Tasks.TaskName, Tags.TagName
FROM dbo.TasksTagList TTL
    INNER JOIN dbo.TagListTags TLT ON TTL.TagListID = TLT.TagListID
    INNER JOIN dbo.Tags ON TLT.TagID = Tags.TagID
    INNER JOIN dbo.Tasks ON TTL.TaskID = Tasks.TaskID;
3
Max Vernon