По-долу е как бих го направил. Имам още няколко коментара в долната част, след като сте видели схемата.
Регистър
LogID - уникален идентификационен номер на дневника
Час - дата/час на събитието
LogType - низ или ID
(страничен коментар, бих отишъл с идентификатор тук, за да можете да използвате таблица със съобщения, показана по-долу, но ако искате бързо n мръсно, можете просто уникален низ за всеки лог време (напр. "Играта започна", "Изпратено съобщение" и др.)
LogActor
LogID - външен ключ
LogActorType - низ или идентификатор (както по-горе, ако идентификаторът ще ви е необходима таблица за справка)
LogActorID – Това е уникален идентификатор на таблицата за типа напр. потребител, група, игра
Последователност - това е подреждане на актьорите.
LogMessage
LogType - външен ключ
Съобщение - дълъг низ (varchar(max)?)
Език - низ (5), за да можете да изключите различен език, напр. "US-en"
Примерни данни (като използвате вашите 3 примера)
Регистър
ID Time LogType
1 1/1/10 1
2 1/1/10 2
3 1/1/10 3
LogActor
LogID LogActorType LogActorID Sequence
1 User 1 1
1 User 2 2
2 User 1 1
2 User 2 2
2 User 2 3
2 Game 1 4
3 User 3 1
3 Group 1 2
LogMessage
LogType Message
1 {0} Made a new friend {1}
2 {0}, {1}, {2} played a game ({3})
3 {0} joined a group ({1})
Потребител
ID Name
1 User A
2 User B
3 User C
Игра
ID Name
1 Name of game
Група
ID Name
1 Name of group
Ето хубавите неща за този дизайн.
-
Много е лесно да се разшири
-
Той се занимава с многоезични проблеми, независимо от актьорите
-
Тя се самодокументира, таблицата LogMessage обяснява какво точно трябва да казват данните, които съхранявате.
Някои лоши неща за това.
-
Трябва да извършите сложна обработка, за да прочетете съобщенията.
-
Не можете просто да погледнете DB и да видите какво се е случило.
Според моя опит добрите части на този вид дизайн надвишават лошите. Това, което направих, за да ми позволя да направя бърз n мръсен преглед на дневника, е да направя изглед (който не използвам за кода на приложението), който мога да гледам, когато трябва да видя какво се случва отзад край.
Кажете ми, ако имате въпроси.
Актуализация – Някои примерни заявки
Всички мои примери са в sqlserver 2005+, уведомете ме, ако има различна версия, към която искате да насочвам.
Вижте таблицата LogActor (Има няколко начина да направите това, най-доброто зависи от много неща, включително разпространение на данни, случаи на използване и т.н.) Ето два:
а)
SELECT
LogId,
COLLESCE(U.Name,Ga.Name,Go.Name) AS Name,
Sequence
FROM LogActor A
LEFT JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
LEFT JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
LEFT JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
ORDER BY LogID, Sequence
б)
SELECT
LogId,
U.Name AS Name,
Sequence
FROM LogActor A
INNER JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
UNION ALL
SELECT
LogId,
Ga.Name AS Name,
Sequence
FROM LogActor A
INNER JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
UNION ALL
SELECT
LogId,
Go.Name AS Name,
Sequence
FROM LogActor A
INNER JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
ORDER BY LogID, Sequence
Като цяло мисля, че а) е по-добре от б) Например, ако ви липсва актьор, тип а) ще го включи (с нулево име). Въпреки това b) е по-лесен за поддръжка (защото операторите UNION ALL го правят по-модулен.) Има и други начини да направите това (напр. CTE, изгледи и т.н.). Склонен съм да го направя като б) и от това, което видях, това изглежда поне стандартна практика, ако не и най-добра практика.
И така, последните 10 елемента в регистрационния файл ще изглеждат по следния начин:
SELECT
LogId,
M.Message,
COLLESCE(U.Name,Ga.Name,Go.Name) AS Name,
Time,
A.Sequence
FROM Log
LEFT JOIN LogActor A ON Log.LogID = A.LogID
LEFT JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
LEFT JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
LEFT JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
LEFT JOIN LogMessage M ON Log.LogType = M.LogMessage
WHERE LogID IN (SELECT Top 10 LogID FROM Log ORDER BY Date DESC)
ORDER BY Date, LogID, A.Sequence
NB – Както можете да видите, по-лесно е да изберете всички елементи от дневника от дадена дата, отколкото последния X, защото за това се нуждаем от (вероятно много бърза) подзаявка.