2017-05-08 7 views
0

Wie würde ich alle Informationen über einen Freiberufler mit dem folgenden Schema auflisten? Einschließlich Nische, Sprache, Markt usw. Das Problem, das ich habe, ist, dass jeder Freiberufler mehrere Einträge für jede Tabelle haben kann. Also, wie würde ich das machen? Ist es überhaupt möglich SQL zu verwenden oder müsste ich dafür meine primäre Sprache (golang) verwenden?Multi-Tabelle, Multi-Zeile SQL select

CREATE TABLE freelancer (
    freelancer_id   SERIAL PRIMARY KEY, 
    ip     inet NOT NULL, 
    username    VARCHAR(20) NOT NULL, 
    password    VARCHAR(100) NOT NULL, 
    email     citext NOT NULL UNIQUE, 
    email_verified  int NOT NULL, 
    fname     VARCHAR(20) NOT NULL, 
    lname     VARCHAR(20) NOT NULL, 
    phone_number   VARCHAR(30) NOT NULL, 
    address    VARCHAR(50) NOT NULL, 
    city     VARCHAR(30) NOT NULL, 
    state     VARCHAR(30) NOT NULL, 
    zip     int NOT NULL, 
    country    VARCHAR(30) NOT NULL, 
); 

CREATE TABLE market (
market_id  SERIAL PRIMARY KEY, 
market_name  VARCHAR(30) NOT NULL, 
); 

CREATE TABLE niche (
niche_id  SERIAL PRIMARY KEY, 
niche_name  VARCHAR(30) NOT NULL, 
); 

CREATE TABLE medium (
medium_id  SERIAL PRIMARY KEY, 
medium_name  VARCHAR(30) NOT NULL, 
); 

CREATE TABLE format (
format_id  SERIAL PRIMARY KEY, 
format_name  VARCHAR(30) NOT NULL, 
); 

CREATE TABLE lang (
lang_id   SERIAL PRIMARY KEY, 
lang_name  VARCHAR(30) NOT NULL, 
); 

CREATE TABLE freelancer_by_niche (
id  SERIAL PRIMARY KEY, 
niche_id  int NOT NULL REFERENCES niche (niche_id), 
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id) 
); 


CREATE TABLE freelancer_by_medium (
id  SERIAL PRIMARY KEY, 
medium_id  int NOT NULL REFERENCES medium (medium_id), 
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id) 

); 

CREATE TABLE freelancer_by_market (
id  SERIAL PRIMARY KEY, 
market_id  int NOT NULL REFERENCES market (market_id), 
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id) 
); 

CREATE TABLE freelancer_by_format (
id  SERIAL PRIMARY KEY, 
format_id  int NOT NULL REFERENCES format (format_id), 
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id) 

); 

CREATE TABLE freelancer_by_lang (
id  SERIAL PRIMARY KEY, 
lang_id   int NOT NULL REFERENCES lang (lang_id), 
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id) 

); 
+0

Von was ich gelesen habe, in Ihrer Frage, haben Sie Probleme beim Verbinden Ihrer Tabellen? –

+0

Eine Antwort und eine wichtige Bemerkung hinzugefügt. – flutter

+0

Können wir sehen, was Sie versucht haben, Blake? Dies fühlt sich momentan ziemlich breit an, da es in der Frage keinen Versuch gibt. – halfer

Antwort

1
SELECT * 
FROM freelancer 
INNER JOIN freelancer_by_niche USING (freelancer_id) 
INNER JOIN niche USING (niche_id) 
INNER JOIN freelancer_by_medium USING (freelancer_id) 
INNER JOIN medium USING (medium_id) 
INNER JOIN freelancer_by_market USING (freelancer_id) 
INNER JOIN market USING (market_id) 
INNER JOIN freelancer_by_format USING (freelancer_id) 
INNER JOIN format USING (format_id) 
INNER JOIN freelancer_by_lang USING (freelancer_id) 
INNER JOIN lang USING (lang_id); 

Und wenn Sie die nicht benötigten Attribute verlieren wollen von Tabellen wie freelancer_by_format beitreten, dann können Sie tun, um diese

SELECT a.ip, a.username, a.password, a.email, a.email_verified, 
a.fname, a.lname, a.phone_number, a.address, a.city, 
a.state, a.zip, a.country, 
b.niche_name, c.medium_name, d.market_name, e.format_name, f.lang_name 
FROM freelancer a 
INNER JOIN freelancer_by_niche USING (freelancer_id) 
INNER JOIN niche b USING (niche_id) 
INNER JOIN freelancer_by_medium USING (freelancer_id) 
INNER JOIN medium c USING (medium_id) 
INNER JOIN freelancer_by_market USING (freelancer_id) 
INNER JOIN market d USING (market_id) 
INNER JOIN freelancer_by_format USING (freelancer_id) 
INNER JOIN format e USING (format_id) 
INNER JOIN freelancer_by_lang USING (freelancer_id) 
INNER JOIN lang f USING (lang_id); 

Und wenn Sie die Spaltennamen zu ändern, zum Beispiel ändern "market_name" nur "Markt", dann gehen Sie mit

SELECT a.ip, ... , 
     d.market_name "market", e.format_name AS "format", ... 
FROM ... 

Bemerkungen In Ihren Join-Tabellen (zum Beispiel freelancer_by_niche) gibt es keine UNIQUE Einschränkung auf freelancer_id, was bedeutet, dass Sie den gleichen Freelancer in mehreren Märkten haben könnten (das ist in Ordnung und wahrscheinlich beabsichtigt).

Aber dann haben Sie auch keine UNIQUE Einschränkung auf beide Attribute (freelancer_id, niche_id), was bedeutet, dass jeder Freiberufler mehrmals in der gleichen Nische sein könnte. ("Joe ist in der Elektronik. Drei Mal"). Sie könnten das verhindern, indem Sie (freelancer_id, niche_id) UNIQUE in freelancer_by_niche machen. Auf diese Weise benötigen Sie auch keinen Ersatz (künstlich) PRIMARY KEY freelancer_by_id (id).

Also was könnte dann schief gehen?

Zum Beispiel vorstellen, dass die gleichen Informationen über freie Mitarbeiterin in der gleichen Nische dreimal (die gleichen Daten Teile der Zeile dreimal):

freelancer_by_niche 
id | freelancer_id | niche_id 
1 |  1  | 1 -- <-- same data (1, 1), different serial id 
2 |  1  | 1 -- <-- same data (1, 1), different serial id 
3 |  1  | 1 -- <-- same data (1, 1), different serial id 

Dann wird das Ergebnis der obigen Abfrage würde jede mögliche Zeile zurückgeben drei (!) mal mit dem gleichen (!) Inhalt, weil freelancer_by_niche kann dreimal mit allen anderen JOIN s kombiniert werden.

Sie können Dubletten eliminieren, indem Sie SELECT DISTINCT a.id, ... FROM ... oben mit DISTINCT verwenden. Was passiert, wenn Sie viele doppelte Zeilen erhalten, zum Beispiel 10 Datenduplikate in jedem der 5 JOIN Tabellen (freelancer_by_niche, freelancer_by_medium usw.)? Sie würden 10 * 10 * 10 * 10 * 10 = 10^5 = 100000 Duplikate bekommen, die alle genau die gleichen Informationen haben. Wenn Sie dann Ihr DBMS bitten, Duplikate mit SELECT DISTINCT ... zu löschen, dann muss es 100000 duplicate rows per different row sortieren, da Duplikate nur durch Sortieren (oder Hashing, aber egal) erkannt werden können. Wenn Sie 1000 verschiedene Zeilen für Freiberufler auf Märkten, Nischen, Sprachen usw. haben, dann bitten Sie Ihr DBMS, 1.000 * 100.000 = 100.000.000 Zeilen SORTIEREN, um die Duplikate bis auf die eindeutigen 1000 Zeilen zu reduzieren. Das sind 100 Millionen unnötige Zeilen.

Bitte machen Sie UNIQUE (freelancer_id, niche_id) für freelancer_by_niche und die anderen JOIN Tabellen.

(Durch Datenduplikate ich meine, dass die Daten (niche_id, freelancer_id) ist die gleiche, und nur die id ist automatisch inkrementierte serielle.mit

SELECT * FROM freelancer_by_lang; 

Jetzt versuchen die SELECT * FROM freelancer INNER JOIN ... Sache

-- this duplicates all data of your JOIN tables once. Do it many times. 
INSERT INTO freelancer_by_niche 
    SELECT (niche_id, freelancer_id) FROM freelancer_by_niche; 
INSERT INTO freelancer_by_medium 
    SELECT (medium_id, freelancer_id) FROM freelancer_by_medium; 
INSERT INTO freelancer_by_market 
    SELECT (market_id, freelancer_id) FROM freelancer_by_market; 
INSERT INTO freelancer_by_format 
    SELECT (format_id, freelancer_id) FROM freelancer_by_format; 
INSERT INTO freelancer_by_lang 
    SELECT (lang_id, freelancer_id) FROM freelancer_by_lang; 

Anzeige der Duplikate:)

können

Sie leicht das Problem, indem Sie die folgenden Aktionen ausführen reproduzieren. Wenn es immer noch schnell läuft, dann tu alle INSERT INTO freelancer_by_niche ... immer wieder, bis es ewig dauert, die Ergebnisse zu berechnen. (oder Sie erhalten Duplikate, die Sie mit DISTINCT entfernen können).

erstellen UNIQUE Daten JOIN Tabellen

Sie Duplikate in Ihrem beitreten Tabellen verhindern kann. Entfernen Sie die id SERIAL PRIMARY KEY und ersetzen Sie es mit einem Multi-Attribut PRIMARY KEY (a, b):

CREATE TABLE freelancer_by_niche (
    niche_id  int NOT NULL REFERENCES niche (niche_id), 
    freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id), 
    PRIMARY KEY (freelancer_id, niche_id) 
); 

(Wenden Sie diese für alle beitreten Tabellen). Der PRIMARY KEY (freelancer_id, niche_id) erstellt einen UNIQUE Index. Auf diese Weise können Sie keine doppelten Daten einfügen (versuchen Sie INSERT s oben, das wird zurückgewiesen, da die Information bereits einmal vorhanden ist. Das Hinzufügen eines anderen Zeitpunkts fügt keine weiteren Informationen hinzu UND würde Ihre Abfrage-Laufzeit viel langsamer machen).

nicht eindeutiger Index auf dem anderen Teil der JOIN Tabellen Mit PRIMARY KEY (freelancer_id, niche_id) schafft Postgres einen eindeutigen Index für diese beiden Attribute (Spalten). Zugriff auf oder Beitritt durch freelancer_id ist schnell, weil es zuerst im Index ist. Der Zugriff auf oder die Verbindung mit freelancer_by_niche.niche_id erfolgt langsam (vollständiger Tabellenscan unter freelancer_by_niche).

Daher sollten Sie auch einen INDEX für den zweiten Teil niche_id in dieser Tabelle freelancer_by_niche erstellen.

CREATE INDEX ON freelancer_by_niche (niche_id) ; 

schließt sich dann in dieser Tabelle auf niche_id auch schneller sein, weil sie durch einen Index beschleunigt werden. Der Index macht Abfragen (normalerweise) schneller.

Zusammenfassung

Sie haben ein sehr gutes normalisierte Datenbankschema! Es ist sehr gut. Aber kleine Verbesserungen können gemacht werden (siehe oben).

+0

Ich versuche eine einfache Lösung zu geben. Er ist ein Anfänger. Natürlich gibt es dafür bessere Möglichkeiten, aber sie sind komplexer. –

+0

Das sieht nach einer guten Antwort aus. Ich möchte jedoch hinzufügen, dass es zwar in Ordnung ist, den Leuten zu zeigen, wie das Abstimmungs-/Akzeptanzsystem funktioniert, aber in den Kommentaren, wenn sie glauben, dass sie nicht wissen, wie man es benutzt, schrecken wir generell von expliziten Ersuchen um Stimmen in den Beiträgen ab. Wir mögen es, hier vernünftig zu sein. – halfer