JOINs oder NULLable?

VanHellsehn

Erfahrenes Mitglied
Hallo zusammen,

ich bin gerade dabei eine kleine Verwaltung zu Programmieren und möchte dabei ein Activity-Log führen. D.h. wenn zum Beispiel ein Nutzer X ein Kommentar schreib oder ein Benutzer zu einer Resource hinzugefügt wird.

So weit so gut jetzt meine Frage. Ist es nun intelligenter ein Layout wie folgendes zu benutzen:

Code:
+----+---------------+-------------+---------+------------+------------+---------------------+
| id | activity_type | resource_id | user_id | comment_id | user_added |      timestamp      |
+----+---------------+-------------+---------+------------+------------+---------------------+
|  1 | comment       |           1 |       1 | 1          | NULL       | 2015-03-15 12:11:15 |
|  1 | user_added    |           1 |       1 | NULL       | 2          | 2015-03-15 12:11:15 |
+----+---------------+-------------+---------+------------+------------+---------------------+

Oder für jeden Activity-Typ eine eigene Tabelle mit den jeweiligen Attributen und dann alle auf die resource_id joinen?
 
Ich würde das in eine eigene Tabelle packen schon auf Grund der Normalisierungsregeln (3te oder 4te Normalform). Somit lädts du nur die Kommentare zum jeweilgen Thema:

Tabelle 'comments'
id (pk)
threadid (fk)
userid (fk)
comment
timestamp
 
Hallo,

wenn man dein Design so ansieht, dann stimme ich Fragenfrager voll und ganz zu. Allerdings kannst du es auch anders lösen (kommt aber dann ganz darauf an, welche verschiedenen Typen es gibt). Wenn es ungefähr so bleibt, dann würde ich es folgendermaßen machen:

Tabelle 'User' erklärt sich von selbst.
Tabelle 'Activity_Types' mit den verschiedenen Typen, dazu je eine Id und evtl. weitere Spalten für Beschreibung etc. (falls du das brauchst).
Tabelle 'Log' (oder wie auch immer du sie nennen willst) mit:
  • id
  • user_id (der user, der die Aktion ausgeführt hat)
  • activity_typ_id
  • timestamp
  • info (kannst du ja auch anders nennen)
Das Info Feld ist an dieser Stelle nun abstrakt in der Hinsicht, dass ohne die activity_typ_id nicht ersichtlich ist, was hier steht. War es ein Kommentar, wird hier die Id zu eben diesem Kommentar stehen. War es ein neuer User, wird dort die Id des Users stehen. Wenn du aber vorher definierst, welche Info für welche Activity erwartet wird, finde ich die Lösung eleganter als für jeden Activity Typ einen eigene Log Tabelle zu haben.
(Außerdem kannst du ja trotzdem nur die Kommentare bzw. Infos zu dem jeweiligen Thema laden, indem du in deiner WHERE Klausel z.B. ein activity_typ_id = 1 einfügst.)

Gruß
Daniel
 
Danke für die Antworten.
ch würde das in eine eigene Tabelle packen schon auf Grund der Normalisierungsregeln (3te oder 4te Normalform).
So habe ich auch gedacht nur werden es dann etwas mehr Tabellen denke ich.

Also ich habe Projekte und zu diesem Projekt können folgende Aktivitäten auftreten: Ein Kommentar wurde verfasst, ein Nutzer arbeit mit am Project der Status eines Projects oder einer Teilaufgabe dieses Projekts ändert sich.

Das wären dann 4 Tabellen nur für das Activitylog.

Das Info Feld ist an dieser Stelle nun abstrakt in der Hinsicht, dass ohne die activity_typ_id nicht ersichtlich ist, was hier steht. War es ein Kommentar, wird hier die Id zu eben diesem Kommentar stehen. War es ein neuer User, wird dort die Id des Users stehen. Wenn du aber vorher definierst, welche Info für welche Activity erwartet wird, finde ich die Lösung eleganter als für jeden Activity Typ einen eigene Log Tabelle zu haben.

So geht mir die möglichkeit Joins zu erstellen verloren. Sagen wir ich habe mit User-1 User-2 zu Projekt-A hinzugefügt. So möchte auch all diese Daten haben und hätte kein Möglichkeit diese zu Joinen.

Grüße Marv
 
So geht mir die möglichkeit Joins zu erstellen verloren. Sagen wir ich habe mit User-1 User-2 zu Projekt-A hinzugefügt. So möchte auch all diese Daten haben und hätte kein Möglichkeit diese zu Joinen.

Verstehe ich jetzt nicht ganz, evtl. reden wir aber auch gerade aneinander vorbei. Ich hab das mit den Projekten auch anfangs nicht ganz verstanden jetzt wurde es verständlicher. Also ein Projekt ist quasi wie du in deinem Anfangspost geschrieben hast eine Resource oder?

Nehmen wir an, das Hinzufügen eines Users ist Activity Id 1, dann wäre dein Eintrag wenn User 1, User 2 zu Projekt 1 hinzufügt folgender:
Code:
+----+------------------+-------------+---------+------+---------------------+
| id | activity_type_id | resource_id | user_id | info |      timestamp      |
+----+------------------+-------------+---------+------+---------------------+
|  1 |                1 |           1 |       1 |    2 | 2015-03-15 12:11:15 |
+----+------------------+-------------+---------+------+---------------------+
In diesem Fall ist Info einfach die Id des hinzugefügten Users, also 2. Über den Join kriegst du den entsprechender User aus der User-Tabelle (oder das Projekt über die resource_id usw. usw.).

Erstellt nun der hinzugefügte User 2 einen Kommentar zu diesem Projekt, erhälst du folgenden Eintrag (Kommentar beispielsweise Activity Id 2):
Code:
+----+------------------+-------------+---------+------+---------------------+
| id | activity_type_id | resource_id | user_id | info |      timestamp      |
+----+------------------+-------------+---------+------+---------------------+
|  2 |                2 |           1 |       2 |    1 | 2015-03-15 12:15:15 |
+----+------------------+-------------+---------+------+---------------------+
Das Projekt ist immer noch Id 1 (resource_id), der User, der die Aktion ausgeführt hat diesmal aber der zuvor hinzugefügte mit der Id 2. Unter Info steht in diesem Fall die Id zur Kommentar Tabelle.

Und was nun genau im Info Feld steht, bzw. mit welcher Tabelle der Join dann Sinn macht, musst du wie gesagt vorher für die Activities definieren.
Also hast du doch alles was du zum Joinen brauchst da oder nicht?


Gruß
Daniel
 
Das Problem ist ja das Info mehrdeutig ist so das man keinen JOIN machen kann. Das Prinzip von dir habe ich schon verstanden.

Aber macht es nicht mehr Sinn eine Spalte user_id_2, comment_id, task_id zu haben die Nullable sind? Ja kann man wenigstens einen eindeutigen Join erstellen. Aber genau das ist ja meine Frage was macht am meisten Sinn? Arbeiten könnte ich mit jeder Lösung doch suche ich die schönste und performativste.

Grüße Marv
 
Natürlich kannst du weiterhin deinen Join machen, nur musst du halt auf die Activity Id aufpassen:
Wenn die Activity Id aussagt, dass es sich um einen Kommentar handelt, bei dem in Info die Kommentar Id gespeichert wird, dann macht ein Join mit der User Tabelle natürlich wenig Sinn. Während bei deinen Nullable Spalten die Null-Werte automatisch aus dem Join draußen sind, musst du eben zusätzlich in deinem WHERE auf die Activity Id abfragen.

SQL:
SELECT u.Name, p.Name, l.timestmp
FROM Log l
INNER JOIN User u ON l.Info = u.Id
INNER JOIN Projekt p ON l.resource_id = p.Id
WHERE l.ActivityId = 2

Wieder angenommen:
  • User ist deine Tabelle mit den Usern (Spalten Id, Name, ...)
  • Projekt ist deine Tabelle mit den Projekten / Resourcen (Spalten Id, Name, ...)
  • Log ist deine Tabelle in der du die Aktionen loggst (Spalten Id, resource_id, Info, timestmp, ...)
  • ActivityId 2 => Neuer User hinzugefügt
Mit diesem Select würdest du erhalten, welcher User wann zu welchem Projekt hinzugefügt wurde.


Gruß
Daniel
 
Das es möglich ist einen JOIN zu machen ist mir bewusst. Aber ich würde gerne z.B. bei nem Projekt alle aktivitäten der letzten 5 Tage oder so anzeigen. Da kann ich die Abfrage doch nicht mit:
WHERE l.ActivityId = 2
eingrenzen. Aber das muss ich ja wenn ich das nach dieser Logik mache? Oder übersehe ich was?

Mein Ziel ist es halt eine Übersicht über die letzten Aktivitäten zu bekommen und ich möchte dafür keine 3 Select (oder Inner-Selects) ausführen.

Grüße Marvin
 
Du musst statt der Abfrage nach der Aktivitäts-ID eine Abfrage nach dem Zeitraum machen. Dann ist es auch egal, welche Aktivitäts-ID die haben. Die brauchst Du dann nur, um den Wert in "Info" korrekt interpretieren zu können.
 
Mein Ziel ist es halt eine Übersicht über die letzten Aktivitäten zu bekommen und ich möchte dafür keine 3 Select (oder Inner-Selects) ausführen.

Wie einfach nur crack schon sagte: Dann lässt du in dem Fall eben die Activity Id weg. Dann bekommst du ja alle Aktivitäten. Außerdem, wenn es dir darum geht, ist es sowieso die elegantere Methode, als viele Tabellen zu haben (für jede Aktivität eine), weil du nämlich genau dann pro Tabelle ein Select hättest und deine Werte summieren müsstest. So machst du nur auf die eine Tabelle deine Abfrage und erhälst alle Aktivitäten.

Vielleicht habe ich mich auch etwas ungeschickt ausgedrückt, aber einfach nur crack hat das Prinzip verstanden:
  • Willst du alle -> keine Eingrenzung.
  • Willst du nur einen bestimmten Typ -> WHERE Activity Id = <n>.
  • Willst du wissen, wie du Info überprüfen bzw. joinen musst -> schau die Activity Id an, bzw. bau deine Query bei solchen Joins mit dem genannten WHERE auf. Solche Joins wären bei allen Aktivitäten sowieso sinnlos, da sie nur vorkommen, wenn du z.B. bei hinzugefügten Usern nicht nur die UserId, sondern auch den Namen haben möchtest. In dem Fall macht der Join aber ja eh nur bei der einen Aktivität einen Sinn, wo ein User hinzugefügt wird.

Gruß
Daniel
 
Zurück