SQL Loginsystem Datenstruktur

@DerEineDa:
Stimmt, mein Fehler (Zorro und Manager), das waren aber auch nur Platzhalter für die eigentlichen Abfragekriterien. Das das DBMS für einen PrimaryKeys implizit einen UniqueKey und NOT NULL Constraints erzeugt, ist mir sehr geläufig. Anders sieht es aber bei den ForeignKeys aus. Die UniqueKey/ForeignKeys für die RELATIONS Tabelle würde ich dennoch aus 2 Gründen bevorzugen:
1. In der Praxis arbeitet es wie der zusammengesetzte Primary Key
2. Diverse Reporting Tools, die das Schema einer Datenbank analysieren, können jetzt die Beziehungen der 3 Tabellen richtig auflösen, da die notwendigen Informationen über die ForeignKeys zur Verfügung gestellt werden können, was meines Erachtens bei einem zusammengesetzten Primary Key nicht der Fall sein kann.

Ich habe mich mal hingesetzt und meine alten Unterlagen durchgeforstet und siehe da es ist tatsächlich so das ich diesen Typ von PK gelernt habe, aber auch gleich wieder links liegen lies aus oben genannten Gründen. Das war vor ca. 10 Jahren. Mist, wo ist die Zeit geblieben??? Danke für die kleine Reise in die Vergangenheit... ;)
 
Zuletzt bearbeitet:
Dann machst du das immernoch nicht richtig, wenn du die Spalten nicht mit einem PK versiehst, sondern Unique und FK gibst.

Unique ist wie gesagt durch PK sowieso gegeben. Außerdem hält dich nichts davon ab, auf beide Spalten zusätzlich als FK zu definieren - das sind sie ja auch. Der Primärschlüssel ergibt sich aus beiden Spalten zusammen, jede Spalte für sich genommen ist aber trotzdem auch ein FK auf die Primärschlüssel der USERS und GROUP-Tabellen.

Ein zusammengesetzter Primärschlüssel hält dich nicht davon ab die einzelnen Attribute des zusammengesetzten Primärschlüssels noch als Fremdschlüssel zu definieren. Das solltest du selbstverständlich auch unbedingt tun!

Im Anhang ein kleiner Ausschnitt eines ER-Diagrammes zu einer Datenbank, die ich im Rahmen meines Studiums im Fach Multimedia-Datenbanken erstellt habe. Genau das gleiche n:m-Szenario: Die Tabelle "img2desc" hat einen zusammengesetzten Primärschlüssel, wobei die Attribute "id_image" und "id_descriptor" Fremdschlüssel auf die benachbarten Tabellen sind. Das ist aufgrund der referenziellen Integrität natürlich auch dringend erforderlich. Gut zu sehen hier auch die durchgezogenen Linien auf diese Tabelle (die bei deiner "Methode" höchstwahrscheinlich nicht vorkommen, da das Tool die Tabelle nicht als "Zwischentabelle" erkennen würde).

Das Diagramm wurde von einem Tool automatisch aus der bestehenden Datenbank generiert. Wie du siehst ist das kein Problem. Ich hoffe deine Gründe gegen einen zusammengesetzten Primärschlüssel überzeugend zerschmettert zu haben ;) So wie du das machst, würde mein DB-Prof dir deine Datenbank direkt um die Ohren hauen.

Ich denke mir das mit dem zusammengesetzten Primärschlüssel nicht aus. In solchen Situationen macht man das einfach so. Das ist vom Erfinder auch ganz sicher so gedacht :)
 

Anhänge

  • mediadb.gif
    mediadb.gif
    7,4 KB · Aufrufe: 111
Zuletzt bearbeitet:
@DerEineDa:
"Zerschmettert" wäre ein etwas zu harter Begriff. Ganz ehrlich, wenn mir jemand etwas um die Ohren hauen will, dann soll er es machen. Da macht er einen großen Fehler. Denn es gibt immer Situationen, wo sich diese brachiale Methode der "Erziehung" rächen wird. Diejenigen, die das mit mir schon gemacht haben, haben das schwer bereut. Ich meine nicht, das ich da rabiat geworden bin, sondern vielmehr habe ich sie dann an anderer Stelle bei weitem überholt und schlicht und ergreifend wie Anfänger da stehen lassen. Das machten Sie einmal, danach waren die Fronten geklärt und die Zukunft wesentlich rosiger. Es gibt immer jemanden der noch ein kleines Quentchen mehr über eine Sache weiß - so ist das Leben, hart aber fair. ;) Soviel zu dem.

Zurück zum Thema: Was du schreibst macht Sinn und ich werde das mal bei Gelegenheit verifizieren. Ansonsten danke für den Tipp... :-)

Grüße Rossibaer
 
War vielleicht etwas hart ausgedrückt. Aber es gibt eben einfach manchmal Methoden, die man einfach so anwendet, weil das nunmal so gemacht wird. Dies ist ein Beispiel dafür. Alles andere ist einfach nicht im Sinne des Erfinders und somit mindestens seltsam, wenn nicht sogar schlecht.
 
Aber es gibt eben einfach manchmal Methoden, die man einfach so anwendet, weil das nunmal so gemacht wird. Dies ist ein Beispiel dafür.

Prinzipiell hast du Recht und ich stimme da mit Dir überein.

Alles andere ist einfach nicht im Sinne des Erfinders und somit mindestens seltsam, wenn nicht sogar schlecht.

Seltsam ok, schlecht, da bin ich anderer Meinung über Seltsames und deren Auswüchse. Wie entstanden dann Computerspiele? Doch wohl letzendlich aus dem Drang die Machine für etwas zu verwenden, was so nicht vorgesehen oder im Sinne des Erfinders war. Aber sei es drum, ich will jetzt keine große Diskussion draus machen. Im übrigen bewahrheitet sich hier wieder einmal der Satz: Viele Wege führen nach Rom.

Grüße Rossibaer

PS: Falls ich mal vor einem für mich unlösbaren Problem mit SQL / RDBMS stehe, werde ich dich dann fragen. Ok?
 
Im Prinzip gebe ich dir Recht: Solange man eine Lösung findet, die ans Ziel führt, ist das in Ordnung. Einspruch erhebe ich erst, wenn die Lösung gravierende Nachteile mit sich bringt. Da in dem Fall ein PK wie gesagt sowieso nichts anderes ist als ein indiziertes UNIQUE-NOT NULL-Attribut ist deine Lösung sogar im Grunde die gleiche wie meine. Nur eben irgendwie seltsam :)

Bei Fragen immer fragen. Gerade im DB-Bereich fühle ich mich sehr fit und helfe gern. Hatte ja auch Jahre langen Unterricht da drin und finde es nach wie vor ein sehr faszienierendes Thema.
 
Hi,
ich weiß das Thema ist vorbei aber ich hätte da eine Frage an unsern DB-Meister :D

Also ich habe eine Tabelle "content" und eine Tabelle "categories".
Innerhalb der Content Tabelle gibt es eine Spalte "Categorie" und "SubCategorie".
Während "Categorie" immer eine ID der Tabelle "categories" beinhaltet, kann SubCategorie auch NULL sein, zwar dann, wenn es einfach keine Unterkategrie gibt.
Mein Problem, wie kreige ich "content" inklusive der Namen der Kateogrie (und ggf. SubCategorie) in einer Abfrage. Das mit Kategorie ist kein Problem (Join), aber eine 'Eventuelle' SubCategorie bringt mich zum verzweifeln.
Hier mal mein Ansatz:
Code:
SELECT
    CON.*,
    CAT.*,
    USER.ID AS user_id,
    USER.User AS user_name,
    IFNULL(CON.SubCategorie,0) AS scat_id,
    IF(CON.SubCategorie = SCAT.cat_id, SCAT.cat_title, 0) AS scat_title
FROM 
    `oa_content` AS CON,
    `oa_content__cat` AS CAT,
    `oa_content__cat` AS SCAT,
    `oa_user` AS USER
WHERE
    CON.`ID` = '1' AND
    CON.`Visibility` = '1' AND
    CON.`Author` = USER.ID AND
    CON.`Categorie` = CAT.cat_id AND
    IF(ISNULL(CON.SubCategorie),0,CON.SubCategorie) = 
    IF(ISNULL(CON.SubCategorie),0,SCAT.cat_id)

Das klappt im Falle einer SubCategorie, hier beim Content ID = 1.
Doch bei einer anderen Content ID (z.B. 4) wo es KEINE SubCategorie ist, bekomme ich 3 selbe Ergebnisse mit scat_title und scat_id = 0, so soll es sein. Aber nicht 3 selbe Ergebnisse. Mir ist bewusst, dass die 3 Ergebnisse wegen den 3 Kateogrien kommen.
Zwar kann ich das mit "LIMIT 1" lösen, und so funktioniert es dann 'perfekt'. Doch ist das überhaupt nur eine riesen Umweg :D Hast du eine Lösung parat? :D
 
Zuletzt bearbeitet:
Ich bin mir nicht ganz sicher, aber für mich hört sich das nach einem klassischen Fall für einen Outer-Join an. Falls ich mich irre und dich nicht ganz verstanden habe, kriegen wir das aber notfalls definitiv mit einer Unterabfrage hin. Erstmal mit Outer-Join:

Code:
SELECT 
    con.ID AS content_id,
    user.ID AS user_id,
    user.User AS user_name,
    cat.title AS cat_title, -- heißt die Spalte "title"???
    scat.title AS scat_title
FROM
    oa_content AS con
JOIN
    oa_user AS user ON con.Author = user.ID
JOIN
    oa_content__cat AS cat ON con.Categorie = cat.cat_id
LEFT JOIN
    oa_content__cat AS scat ON con.SubCategorie = cat.cat_id

Du hast übrigens eine schreckliche Namensgebung. Bei Content heißt der Primärschlüssel "ID" und bei Categorie plötzlich "cat_id"??? Außerdem komische Groß-Kleinschreibung und andere komische Sachen. Du solltest dir schon überlegen, ob du die Attribute (Spalten) nun groß oder klein schreiben willst, oder mit Unterstrich oder zusammen. Bei der Tabelle "oa_user" lautet der Primärschlüssel anscheinend "ID", bei "oa_content__cat" dann aber wie gesagt anscheinend "cat_id". Doch wieso heißt dann die Spalte "SubCategorie" in "oa_content" nicht logischerweise "sub_category"? Solche Inkonsistenzen machen das ganze extrem schwer zu durchschauen.

Wenn ich in den Beispielen die Spalten falsch benannt habe, musst du das selber anpassen, denn ich steige da nicht durch.....

So, warum ist da hinten dran nun ein LEFT-JOIN? Darum, weil wir die bis dahin mühevoll zusammengebastelte Relation komplett erhalten wollen. Es sollen also auch noch die Tupel (Zeilen) im Ergebnis enthalten sein, bei denen SubCategorie NULL ist. Damit diese Zeilen beim JOIN nicht verschwinden, machen wir hier ein LEFT JOIN.

Eine andere gute Möglichkeit wären Unterabfragen. Beispiel:

Code:
SELECT
    con.id,
    (SELECT cat.title FROM oa_content__cat AS cat WHERE cat.cat_id = con.Categorie) AS cat_title,
    (SELECT scat.title FROM oa_content__cat AS scat WHERE scat.cat_id = con.SubCategorie) AS scat_title
FROM oa_content AS con

Hab in dem Beispiel der Einfachheit halber die User-Tabelle rausgelassen und wieder geraten, ob die Titel-Spalte von Categorie "title" heißt. Bei Fragen dieser Art bitte in Zukunft auch die Spalten benennen oder idealerweise ein ER-Diagramm anhängen.

Wegen deiner Notation mit den `-Zeichen gehe ich davon aus, dass du MySQL benutzt. Unterabfragen kann MySQL seit Version 4.1.

Beide Beispiele müssten theoretisch funktionieren. Da ich an einigen Stellen raten musste, wie dein DB-Schema genau aussieht, muss aber vielleicht ein bisschen was angepasst werden. Mit mehr Input deinerseits kriegen wir das aber sicher so hin.
 
Zuletzt bearbeitet:
Hi Eagle,

kurz gesagt: Ein Outer Join wäre die Lösung, wie in dem 1. Beispiel von DerEineDa. Je nachdem in welcher Tabelle keine Zeile vorhanden sein kann, musst du dann entweder LEFT OUTER JOIN (oder kurz LEFT JOIN) oder RIGHT OUTER JOIN (RIGHT JOIN) verwenden. Hier noch ein kleiner Tipp zu den Namenskonventionen aus eigener Praxis: Verwende für ID Spalten immer das Schema TableName_ID, z.B. Tabelle USER dann USER_ID oder Tabelle AUFTRAG dann AUFTRAG_ID. Dann brauchst du in den abhängigen Tabellen nicht einen neuen Namen erfinden und weißt stets was in der Spalte drin ist...

Grüße Rossibaer

@DerEineDa:
Gehst du auch mal schlafen? Ist ja immerhin 4:00 Uhr gewesen als du deine Antwort schriebst... ;)
 
Zuletzt bearbeitet:
ok, ich geh jetzt arbeiten und schau's mir später an.

@DerEineDa
Ja MySQL. Hätte ich sagen sollen^^.

@Rossibaer, das mit dem TableName_ID mach ich schon länger ;) Nur ist gerade DIESE Tabelle bissle veraltet :) Werde ich ggf. umbennen.

Danke an euch beiden!
 
Hm eigentlich eine gute Gelegenheit mal hier bisschen aufzuräumen :D ja das passiert halt wenn man ständig Eins nach dem andern hinzufügt^^.
Anfangs war ein ganz anderes Kategorien-System gedacht (wie ich es jetzt in noch in der Navigation nutze). Ich krieg meistens solche 'Ideen'/'Geistesblitze' für Methoden oder Umsetzungen zu schnell, um logisch drüber nachzudenken wie ich es benennen soll, sondern richte es provisorisch ein. Und 2 Jahre später steht's immer noch so da :)

Edit: Um meine Glaubwürdigkeit etwas zu untermauern, paar bilder^^.
Beim einen seht ihr, weshalb ich viel im Kopf behalten muss für das Projekt. Auch ein Diagram ist dabei.

Ahja, bitte stütze dich jetzt nicht auf den Aufbau der Namen, ich überarbeite sie jetzt mal endlich.

@Rossibaer, wem sagts du das :D
 

Anhänge

  • admin.gif
    admin.gif
    31,4 KB · Aufrufe: 112
  • diagram.gif
    diagram.gif
    25,4 KB · Aufrufe: 115
  • dir.gif
    dir.gif
    16,5 KB · Aufrufe: 98
  • todo_list.gif
    todo_list.gif
    7,6 KB · Aufrufe: 83
Zuletzt bearbeitet:
Dann bist du entschuldigt :) Ich kenne das nur zu gut, an alte Datenbanken anbauen zu müssen, die oft auch von anderen Leuten gemacht wurden.

Ich finde die Lösung mit den Unterabfragen aber nun nicht unbedingt schlechter als die mit dem outer join. Müsste man mal mit den entsprechenden SQL-Befehlen analysieren, welche Methode effizienter ist. Muss aber jeder für sich selber entscheiden.

@Rossibaer: Ich bin Student und es sind Semesterferien. Das erklärt meine Zeiten doch ganz gut, oder? :D
 
Ich finde die Lösung mit den Unterabfragen aber nun nicht unbedingt schlechter als die mit dem outer join. Müsste man mal mit den entsprechenden SQL-Befehlen analysieren, welche Methode effizienter ist. Muss aber jeder für sich selber entscheiden.

Interessanterweise werden Subselects bei SQLServer in Joins gewandelt, bevor sie ausgeführt werden. Man kriegt nicht viel davon mit. Macht das DBMS selbst. Dieses Verhalten stützt meine Theorie das jeder Subselect mit einem Join dargestellt werden kann.

@DerEineDa: Semesterferien, du glücklicher, ich muss bei der Hitze arbeiten und das 8 bis 10 Stunden am Stück. Von wegen Wirtschaftskrise - der Laden brummt!
 
Zuletzt bearbeitet:
Ich habe einige Beispiele gehabt, die sich unmöglich durch Joins ausdrücken lassen, sondern ausschließlich durch Subselects. Ich habe gerade keines zur Hand, aber ich bin mir ziemlich sicher, dass es viele solcher Szenarien gibt.

Edit: Ich weiß, dass das keine Argumentation ist :) Ich werde nochmal darüber nachdenken und vielleicht die alten Unterlagen raussuchen, mit denen wir Unterabfragen gelernt haben. Ich bin mir sicher da waren Aufgaben dabei, die sich anders nicht lösen ließen.
 
Zuletzt bearbeitet:
Teils teils, war von mir zu pauschal. Für Subselects in der WHERE Bedingung gilt dies laut meiner Erfahrung, bei SubSelects in der Spaltenauflistung ist dies nicht der Fall. Ok, schau mal nach den Beipielen, ich bin gespannt und warte...

Hier noch ein kleiner Goodie von MS SQLServer zum Wach werden ;):

Code:
DECLARE @Text VARCHAR(8000)
SELECT @Text=ISNULL(@Text+', ', '')+NAME FROM ADDRESSEN WHERE FIRMA='Sonnenschein AG'
SELECT @Text
GO

Grüße Rossibaer

PS: Was lernt man daraus, man braucht nicht immer einen Cursor. Oracle verhält sich anders. MySQL ist mir unbekannt und ich will auch nicht extra für einen Test MySQL installieren. Vielleicht kann das ja mal einer für mich testen und dann kurz Bescheid geben.
 
Zuletzt bearbeitet:
@Rossibaer
wüsste nicht wie ich das in MySQL ausführen sollte^^ (zumindest nicht über PHPmyAdmin).

So allgemein, hab jetzt eine neue Ordnung geschaffen (Anhang).

@DerEineDa
Es hieß "cat_title" nicht "title" ;) Das mit dem SubQueries hat gut geklappt danke! Aber ich wäre intressiert das auch mit "Outer Join" oder wie's heißt, hin zu bekommen :D
 

Anhänge

  • update.png
    update.png
    43,5 KB · Aufrufe: 101
Eagel: Im Grunde ist der SQL Block recht einfach gehalten. Es geht darum eine Variable zu definieren, dann das SELECT auszuführen und am Ende den Inhalt der Variable auszugeben. Ist reine SQLServer Syntax, wie ich das in MySQL mache, ist mir gänzlich unbekannt, da ich beruflich nichts mit diesem DBMS zu tun habe. Privat habe ich mir "zum Spielen" SQLServer 2005 Express installiert, war halt bei Visual Studio dabei. Zum Ausführen ist ein SQL-Abfragewerkzeug ähnlich dem QueryAnalyzer (SQLServer) oder SQLPlusWorksheet (Oracle) nötig, das auch Anweisungsblöcke verarbeiten kann. Typisch ist für SQLServer das GO welches einen solchen Block abschließt, analog zu Oracles "/". Die einzelnen Befehle werden bei SQLServer nicht getrennt, bei Oracle ist das Semikolon zwingend erforderlich.

Der Oracle Code sollte ungefähr so lauten:

Code:
BEGIN DECLARE sText VARCHAR(8000);
  BEGIN
    SELECT NVL( sText || ', ', '' ) || NAME INTO sText FROM ADDRESSEN WHERE FIRMA = 'Sonnenschein AG';
    -- wie war doch gleich der Befehl um in den Output zu schreiben? Ich weiß es nicht mehr, zu lang her!
    -- OUTPUT sText
  END;
END;
/

Falls jemand etwas damit anfangen kann und das in MySQL transformiert, dann wäre ich da glücklich, wenn er das posten könnte. Ansonsten ist es auch nicht schlimm...

Grüße Rossibaer
 
Zuletzt bearbeitet:
@Eagle-PsyX-

Wo ist denn das Problem mit der LEFT JOIN-Variante? Mein Beispiel von oben sollte eigentlich schon annähernd so funktionieren.

@Rossibaer

Die Prozedur-Syntax von MSSQL ist mir nicht geläufig, da ich niemals damit gearbeitet habe. Im Grunde kenne ich nur PostgreSQL, Sybase und einigermaßen auch MySQL gut genug :)
 
Zuletzt bearbeitet:
Zurück
Oben