Verknüpfung mit einer Tabelle von drei möglichen

TonySunshine

Benutzer
Beiträge
10
Hallo zusammen,

ich bin eigentlich recht fit in SQL habe jetzt aber mal ein Problem bei dem ich Hilfe gebrauchen könnte.

Auf meiner website kann man sich mit Facebook, Google Plus oder Twitter anmelden, dafür habe ich jeweils drei Tabellen erstellt und referenziere von meiner Tabelle User auf die entsprechende Id.

Mein Problem ist jetzt wie ich ein möglichst kurze und schnelle Abfrage machen kann sodass ich von der UserId auf den Usernamen komme.

Meine erste überlegung war ein UNION über alle drei Tabellen, das finde ich allerdings sehr kompliziert und wahrscheinlich ist es auch nicht besonders schnell.

Hier mal meine Struktur:
sql.jpg
Ich habe beispielsweise die UserId 12 und möchte dazu per SQL den Usernamen, weiß aber nicht das User 12 ein Facebook User ist. Jemand eine Idee?

Vielen Dank
Dennis
 
Werbung:

akretschmer

Datenbank-Guru
Beiträge
9.736
Hallo zusammen,

ich bin eigentlich recht fit in SQL habe jetzt aber mal ein Problem bei dem ich Hilfe gebrauchen könnte.

Auf meiner website kann man sich mit Facebook, Google Plus oder Twitter anmelden, dafür habe ich jeweils drei Tabellen erstellt und referenziere von meiner Tabelle User auf die entsprechende Id.

Dein Schema skaliert nicht: wenn morgen ein weiterer Dienst dazukommt, änderst Du ALLES. Mach einfach eine Tabelle für social Media, wo derzeit halt Twitter, Fratzenbuch und Gurgel drin stehen, und eine weitere Spalte in Deiner User-Tabelle mit FK auf die eben genannte Tabelle. Damit löst sich dann auch Dein Problem.
 

TonySunshine

Benutzer
Beiträge
10
Dein Schema skaliert nicht: wenn morgen ein weiterer Dienst dazukommt, änderst Du ALLES.
Genau das hatte ich gehofft nicht machen zu müssen.

Könnte ich nicht in die User Tabelle eine Spalte Network hinzufügen in der "Facebook", "Google" ... steht und mein SQL Befehl dann irgendwie so aufbauen das die Verknüpfung zur richtigen Tabelle automatisch anhand dieser Network Spalte gemacht wird?

Mach einfach eine Tabelle für social Media, wo derzeit halt Twitter, Fratzenbuch und Gurgel drin stehen, und eine weitere Spalte in Deiner User-Tabelle mit FK auf die eben genannte Tabelle. Damit löst sich dann auch Dein Problem.

Ja hatte ich auch drüber nachgedacht, aber ich wollte gerne dem User die Möglichkeit geben zusätzlich zu seinem facebook account, auch seinen Google Account angeben zu können um die Freundesliste beider Netzwerke zu sehen.

Außerdem hätte ich gedacht das es etwas schneller ist, weil die einzelnen Tabellen ja nicht so groß sind wie eine große, oder?
 

akretschmer

Datenbank-Guru
Beiträge
9.736
Genau das hatte ich gehofft nicht machen zu müssen.

Könnte ich nicht in die User Tabelle eine Spalte Network hinzufügen in der "Facebook", "Google" ... steht und mein SQL Befehl dann irgendwie so aufbauen das die Verknüpfung zur richtigen Tabelle automatisch anhand dieser Network Spalte gemacht wird?



Ja hatte ich auch drüber nachgedacht, aber ich wollte gerne dem User die Möglichkeit geben zusätzlich zu seinem facebook account, auch seinen Google Account angeben zu können um die Freundesliste beider Netzwerke zu sehen.

So etwa:

Code:
kretschmer@tux:~$ psql test
Timing is on.
psql (9.2.4)
Type "help" for help.

test=# create table social_media(id int primary key, name text);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "social_media_pkey" for table "social_media"
CREATE TABLE
Time: 362,040 ms
test=*# create table my_users(id serial primary key, name text);
NOTICE:  CREATE TABLE will create implicit sequence "my_users_id_seq" for serial column "my_users.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "my_users_pkey" for table "my_users"
CREATE TABLE
Time: 93,477 ms
test=*# create table user_media (user_id int references my_users, media_id int references social_media, primary key(user_id, media_id));
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "user_media_pkey" for table "user_media"
CREATE TABLE
Time: 68,268 ms
test=*#

Außerdem hätte ich gedacht das es etwas schneller ist, weil die einzelnen Tabellen ja nicht so groß sind wie eine große, oder?

Über welche Größen reden wir? Selbst im 2-stelligen Millionenbereich würde ich mir da noch keine Gedanken machen.
 

ukulele

Datenbank-Guru
Beiträge
4.702
Wenn du nur eine Tabelle zum speichern der Anmeldeinformationen nutzt muss das ja nicht zwigend heißen das auch immer nur eine Anmeldung existiert. Du fügst der Tabelle eine Spalte "Dienst" hinzu die zwischen Google und Co. unterscheidet und ein User kann dann eben mehrere Anmeldungen in dieser Tabelle haben, das skaliert dann wunderbar. Theoretisch kann man so auch Konten für Personengruppen anlegen die aber nicht alle den selben Zugang sondern jeder seinen eigenen verwenden.

In deiner jetzigen Form kannst du mit einem UNION von 3 Selects arbeiten, das sollte kein Problem darstellen. Du kannst natürlich auch mit dynamischem SQL einen Befehl erstellen in dem du andere Bedingungen mit abfragst aber schneller wird das auch nicht als grade 3 Tabellen abzufragen. Die Dauer hierfür sollte weit unter einer Sekunde liegen.
 

TonySunshine

Benutzer
Beiträge
10
So etwa:

Code:
kretschmer@tux:~$ psql test
Timing is on.
psql (9.2.4)
Type "help" for help.
 
test=# create table social_media(id int primary key, name text);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "social_media_pkey" for table "social_media"
CREATE TABLE
Time: 362,040 ms
test=*# create table my_users(id serial primary key, name text);
NOTICE:  CREATE TABLE will create implicit sequence "my_users_id_seq" for serial column "my_users.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "my_users_pkey" for table "my_users"
CREATE TABLE
Time: 93,477 ms
test=*# create table user_media (user_id int references my_users, media_id int references social_media, primary key(user_id, media_id));
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "user_media_pkey" for table "user_media"
CREATE TABLE
Time: 68,268 ms
test=*#

Damit willst du mir sagen das ich eine weitere Tabelle anlegen sollte, damit der Benutzer mehrere Social Network benutzen kann? Hmm ja ok ist auch ne idee, finde es allerdings mit einer Tabelle pro Social Network schöner.

Kann ich nicht sowas in die richtung machen, wie ich mit der Network Spalte in der Tabelle User beschrieben hatte? Irgendwie in die Richtung:
SELECT n.* FROM User u, [u.Network] n WHERE n.Id=u.[u.Network]


Über welche Größen reden wir? Selbst im 2-stelligen Millionenbereich würde ich mir da noch keine Gedanken machen.

Ach echt? Ok ich unterschätze wohl die geschwindigkeit von sql. dann ist die geschwindigkeit kein argument.
 

TonySunshine

Benutzer
Beiträge
10
Wenn du nur eine Tabelle zum speichern der Anmeldeinformationen nutzt muss das ja nicht zwigend heißen das auch immer nur eine Anmeldung existiert. Du fügst der Tabelle eine Spalte "Dienst" hinzu die zwischen Google und Co. unterscheidet und ein User kann dann eben mehrere Anmeldungen in dieser Tabelle haben, das skaliert dann wunderbar. Theoretisch kann man so auch Konten für Personengruppen anlegen die aber nicht alle den selben Zugang sondern jeder seinen eigenen verwenden.

In deiner jetzigen Form kannst du mit einem UNION von 3 Selects arbeiten, das sollte kein Problem darstellen. Du kannst natürlich auch mit dynamischem SQL einen Befehl erstellen in dem du andere Bedingungen mit abfragst aber schneller wird das auch nicht als grade 3 Tabellen abzufragen. Die Dauer hierfür sollte weit unter einer Sekunde liegen.

Mein abfragen sind teilweise eh schon lang und um dann nur den UserNamen herauszubekommen, wollte ich das UNION verhindern zu benutzen. Danach wären meine Abfragen ja alle 3 - n mal so lang wie vorher. Außerdem wollte ich verhindern das ich alle SQL Abfragen anfassen muss, wenn ein weiteres Social Network hinzufüge
 

ukulele

Datenbank-Guru
Beiträge
4.702
Außerdem wollte ich verhindern das ich alle SQL Abfragen anfassen muss, wenn ein weiteres Social Network hinzufüge
In diesem Fall würde ich auf jeden Fall auf eine ein-Tabellen-Lösung wechseln. Tabelle "Logins" enthällt dann ein Fremdschlüssel der auf das Userprofil verweißt, den eigentlichen Login und den jeweiligen Dienst per ID, Kennung oder eben Name, das ist auch nicht so dramatisch. Ein User kann dann mehrere Logins führen, sogar mehrere pro Dienst und bei einem neuen Dienst muss an der Tabellenstruktur nichts geändert werden.
 

TonySunshine

Benutzer
Beiträge
10
naja da ist ja das problem, das ich bei einem neuen social network jedes mal alle meine sql abfragen ändern muss.

die einzige lösung wäre gewesen, wenn ich die verknüpfung anhand des spalten namen hätte machen können z.b in der tabelle "user" gibt es die spalte "google" und wenn in der eine id steht verknüpfe ich diese mit der gleich namigen tabelle "google"
 

ukulele

Datenbank-Guru
Beiträge
4.702
Nein das ist nicht die einzige Lösung, habe ja versucht dir eine ein Tabellen Lösung schmackhaft zu machen.

Natürlich kannst du eine Spalte "google" machen und einen Fremdschlüssel auf die Tabelle "google" verweisen lassen. Aber in diesem Fall musst du ja grade deine Tabellenstruktur und deine Abfragen bei einem neuen Dienst ergänzen. Wenn du das nicht willst macht es überhaupt keinen Sinn eine Tabelle für jeden Dienst anzulegen sondern nur eine Tabelle für alle Dienste zu nutzen.
 

TonySunshine

Benutzer
Beiträge
10
das ich die möglichkeit habe alles in eine tabelle zu machen ist mir klar, auch wie ich eine spalte user.google mit der tabelle google.id verknüpfe ist mir klar. du verstehst nicht was ich meine.

meine frage war ob ich eine spalte "user.name" in der jeweils der wert 'Facebook', 'Google' oder 'Twitter' stehen kann, automatisch dazu bringen kann die spalte "user.facebook" mit der spalte"facebook.id" zu verknüpfen bzw. die spalte "user.google" mit "google.id" usw.

In dem Fall würde ich bei einem neuen network einfach eine neue spalte z.b. "user.linkedin" anlegen und eine neue tabelle "linkedin" und müsste keinen meiner sql abfragen anfassen, weil die automatisch anhand der "user.name" spalte die verknüpfung automatisch machen würde.

ich dachte es gäbe sowas wie:

SELECT n.* FROM User u, [u.Name] n WHERE n.Id=u.[u.Network]
 
Werbung:

ukulele

Datenbank-Guru
Beiträge
4.702
Naja du kannst schon ein SQL Script basteln aber in einer Abfrage geht es definitiv nicht.
Code:
DECLARE    @tabelle VARCHAR(20),
        @char VARCHAR(255)
 
SELECT    @tabelle = u.Network
FROM    [User] u
WHERE    u.id = 123
 
SET        @char = '
SELECT    login
FROM    ' + @tabelle
 
EXEC    @char
Du fragst erst den Inhalt der Spalte mit dem Dienstnamen ab, schreibst ihn in eine Variable, erzeugst das SQL Statement als String (vorsicht, SQL Injection möglich!) und führst das mit EXEC aus.
 
Oben