SQL Tabellenstruktur Frage

lalo

Aktives Mitglied
Hallo,

ich habe da mal eine Frage.
Und zwar geht es z.B. um ein Userprofil bei dem ein User mehrere Interessen oder Sprachen (oder sonstiges)auswählen kann.

Nun habe ich glaube ich bis jetzt 3 verschiedene Wege gesehen diese zu speichern und wollte euch mal fragen, was eurer Meinung nach die Beste ist, auch im hinblick darauf später danach zu suchen..

Variante 1 :

Usertabelle:

CODE
userID | sprache1 | sprache2 | ... | spracheX
-----------------------------------------------------------
1 | 1 | 0 | 0 | 1
2 | 1 | 1 | 1 | 1





Variante 2:

Usertabelle:


CODE
userID | sprachen
------------------
1 | 1,3,5
2 | 1,2,3






Variante 3:

Usertabelle:


CODE
userID | irgendwelche_Felder...
------------------
1 | ...



Sprachtabelle:


CODE
lngID | userID | sprache1 | sprache2 | ... | spracheX
---------------------------------------------------------------------------
1 | 1 | 0 | 1 | 1 | 1
2 | 2 | 1 | 0 | 1 | 1
3 | 9 | 1 | 1 | 1 | 1



...oder gibt es evtl. bessere Möglichkeiten ?

Grüße
lalo
 
Ich empfehle dir, dir mal die Regeln zur Normalisierung von relationalen Datenbanken anzuschauen.

Tabellen - Empfehlung:

Usertabelle:
UserID
weitere Infos

Sprachtabelle:
UserID
SprachID

Sprachreferenz:
SprachID
Sprachbezeichnung

Wobei bei der Sprachtabelle UserID und SprachID den kombinierten Schlüssel darstellen und damit jede Kombo nur einmal vorkommen darf.

Gruß,
Tom

Edit:
Ein kleines Beispiel als Veranschaulichung:

Usertabelle
1 - Peter
2 - Maik

Sprachtabelle
1 - 2
1 - 3
1 - 4
2 - 1
2 - 3

Sprachreferenz
1 - Deutsch
2 - Englisch
3 - Französich
4 - Suaheli

 
Hi,

Danke für die schnelle Antwort, wie gesagt habe ich diese 3 Varianten in anderen Scripts mal gesehen und war mir nicht sicher welches die Vorteilhafteste ist.

Sind die anderen Varianten evtl. performanter ?

Eine Frage zu Deinem Beispiel, ich glaube ich steh da gerade auf dem Schlauch, aber wie bekomme ich denn dort jetzt raus bei wer z.B. Deutsch (2) und Französich (3) spricht, also beides (bzw. alle gesuchten Sprachen) und nicht nur eines ?
 
Bei beliebig großen Grundtabellen für Personen und Sprachen ist die von Thomas genannte strikte Normalisierung erste Wahl.

Falls die Zahl der Sprachen nur relativ gering ist, kann man auch eine Bitcodierung in einer einzigen Integer-Spalte (ohne Verknüpfungstabelle) nutzen:

deutsch = 1
englisch = 2
französisch = 4
italienisch = 8

also immer Potenzen von zwei, das geht bei 4 Byte (= Integer) für bis zu 32 Sprachen.

Dann lassen sich die Sprachen schön als Checkboxen ausgeben, man zählt die Haken einfach zusammen:

deutsch + französisch = 5

Wenn man dann Bitoperatoren nutzt, kann das auch wieder direkt ausgewertet werden:

QUOTE (Spalte & 5) = 5

Jemand spricht deutsch und französisch


QUOTE (Spalte & 5) <> 0

Jemand spricht deutsch oder französisch


Die Varianten 2/3 sind ziemlich Murks, die Variante 1 geht in seltenen Fällen (wenn die Zahl der Details wirklich höchstens 3 ist - hängt aber immer noch von einigem anderen ab).
 
Hallo,

Danke für die ausführliche Antwort !
Die Idee mit der Bitkodierung ist auch wirklich Klasse ;-)
Da es sich aber nicht nur auf 32 Werte begrenzen soll, würde ich dann eher die Lösung von Tom nehmen.

Allerdings habe ich da gerade noch das Problem das ich genau weiß wie ich die Abfrage erstellen muss, das ich z.B. bei einer Suche nur die Leute angezeigt bekomme die Deutsch (2) und Französich (3) sprechen, in Toms Beispiel also nur Person A. Ich mache da irgendwie gerade einen Denkfehler
 
Aus dem Kopf heraus müsste ungefähr das gehen:

CODE
SELECT
user.name, user.id, ...
FROM
user,
user_lang_connection AS conn,
languages AS lang
WHERE
(lang.id=2 OR lang.id=3 OR ... )
AND
conn.lang_id=lang.id
AND
user.id=conn.user_id
GROUP BY user.id



Wobei man nach den Sprach-IDs auch direkt in der Verknuepfungstabelle suchen koennte, dann würde man sich einen Schritt sparen. Wenn man aber zum Beispiel nach den Namen der Sprachen sucht braucht man auch die Sprachen-Tabelle.
 
Na per OR bekomme ich ja alle die 2 oder 3 haben, ich wollte ja nur die angezeigt bekommen bei denen 2 UND 3 vorhanden ist und keine weiteren.
 
Dann könntest du es über zwei Subselects machen:
CODE
SELECT
user.name, user.id, ...
FROM
user
WHERE
user.id IN ( SELECT user_id FROM user_lang_connection WHERE lang_id=2 )
AND
user.id IN ( SELECT user_id FROM user_lang_connection WHERE lang_id=3 )



oder du nimmst das vorherige Kommando und zählst wie oft user.id vorkommt. Wenn du nach zwei Sprachen suchst muss die entsprechende user-row auch zwei mal geladen werden. Wenn der User allerdings nur eine Sprache ausgewählt hat würde die Reihe nur einmal geladen werden. Die Zählvariable kann man dann einfach im WHERE-Abschnitt prüfen z.B. WHERE ... AND count_user_rows=2.
 
Danke für die Hilfe, aber ist das richtige / einzige weg ?
Das war ja nur ein Beispiel, kann ja auch sein das gesucht wird nach 5 Sprachen oder 8 Interessen etc.

Gibt es da keinen Befehl / Möglichkeit das einfacher / eleganter abzufragen ?
 
QUOTE (lalo @ Do 20.11.2008, 16:46) Danke für die Hilfe, aber ist das richtige / einzige weg ?

1.mal ... StartPost Variante 2 .... = übel = schlecht abfragbar = nur über LIKE = bei vielen daten extrem langsam da kein Index möglich

2.zum hiergequoteten
Ich würde einfach bei Änderungen der Sprachen, die angewählten addieren und in eine neue Tabelle rübercopieren, eventuell direkt in die UserTabelle

das ist zwar kontraproduktiv bezüglich Normalisierung ....
aber
wenn man sich streng daran hält alle Infos nur einmal zu haben
und Infos immer und immer wieder "verrrechnet" werden .... da ist es doch für die Performance besser man rechnet einmal und nicht immerundimmer wieder

so oft werden die Spachinfos ja nicht "geändert" ... also, bei änderung "rechnen" und zusatzabspeicherung und dieser dann die Antwort für den Select holen


mehr als 32 Bits?
= mehr als 32 Sprachen?
naja, dann eben aufteilen auf 2 Spalten

id
user
Vorname
Nachname
langBITSeuropaUSuk (und Australien und Russland ... hm könnte auch schon wieder mehr als 32 werden)
langBITSasien1
langBITSasien2
(wieviele Sprachen gibt es? 160 oder 180? oder ...?)

 
Hi,

na ich würde mich ja sonst schon gerne an die von Tom und jAuer vorgeschlagene Variante halten, allerdings weiß ich nicht wie ich dort die besagte Abfrage "richtig" mache. ;-)
 
Zurück
Oben