2017-05-08 105 views
0

如何在給出以下模式的情況下列出有關自由職業者的所有信息?包括利基,語言,市場等。我遇到的問題是每個自由職業者可以爲每個表格輸入多個條目。那麼,我將如何做到這一點?它甚至可能使用SQL,或者我需要使用我的主要語言(golang)嗎?多表,多行SQL選擇

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

從我讀到的,在你的問題中,你無法連接你的表? –

+0

增加了一個答案和一個重要的評論。 – flutter

+0

我們可以看看你嘗試過什麼,Blake?目前這感覺相當寬泛,因爲在這個問題上沒有嘗試或研究。 – halfer

回答

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); 

如果你想減掉多餘的屬性,從連接表像freelancer_by_format,那麼你就可以做到這一點

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); 

如果你想改變列名,例如改變「market_name」只是「市場」,那麼你去

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

備註 在您的連接表中(例如freelancer_by_nichefreelancer_id上沒有UNIQUE約束,這意味着您可以在多個市場擁有相同的自由職業者(這很好,可能是有意的)。

但是你也沒有對(freelancer_id, niche_id)這兩個屬性的約束UNIQUE,這意味着每個自由職業者可能會在同一個生態位多次。 (「喬在電子產品三次」)。 您可以通過freelancer_by_niche中的(freelancer_id, niche_id) UNIQUE來阻止該問題。 這樣你也不需要代理(人工)PRIMARY KEY freelancer_by_id (id)

那麼會出現什麼問題呢?

例如想象大約在同一利基自由職業者相同的信息三次(該行的相同的數據部分三次):

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 

接着上面的查詢的結果將返回每個可能的行因爲freelancer_by_niche可以與所有其他JOIN s組合三次(!)次。

您可以使用以上的DISTINCT消除重複項。 如果您得到許多重複的行,例如5個JOIN表(freelancer_by_niche,freelancer_by_medium等)中的每個表中有10個重複的數據,該怎麼辦?你會得到10 * 10 * 10 * 10 * 10 = 10^5 = 100000重複,它們都有完全相同的信息。 如果您然後要求您的DBMS消除與SELECT DISTINCT ...重複,那麼它必須排序100000 duplicate rows per different row,因爲重複只能通過排序(或哈希,但不介意)來檢測。如果市場,利基,語言等方面針對自由職業者有1000個不同的行,那麼您要求DBMS排序1.000 * 100.000 = 100.000.000行以將重複數降低到唯一的1000行。 這是1億不必要的行。

請使UNIQUE (freelancer_id, niche_id)freelancer_by_niche和其他JOIN表。

(通過重複的數據我的意思是數據(niche_id, freelancer_id)是相同的,只有id是自動遞增的串行。使用

SELECT * FROM freelancer_by_lang; 

現在嘗試SELECT * FROM freelancer INNER JOIN ...事情

-- 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; 

顯示重複的:)

您可以通過以下操作輕鬆重現該問題。 如果它仍然運行得很快,那麼一次又一次地做所有的INSERT INTO freelancer_by_niche ...,直到計算結果需要永久。 (或者你會得到重複的,你可以用DISTINCT刪除)。

創造出獨特的數據連接表

您可以防止您的連接表副本。 取出id SERIAL PRIMARY KEY,並用多屬性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) 
); 

(應用此爲您所有的連接表)。 PRIMARY KEY (freelancer_id, niche_id)將創建一個UNIQUE索引。 這樣你不能插入重複的數據(試試上面的INSERT),將會被拒絕,因爲這些信息已經存在一次,再添加一次不會增加更多的信息,並且會讓你的查詢運行時更慢)。

對JOIN表 隨着 PRIMARY KEY (freelancer_id, niche_id)的另一部分

非唯一索引,Postgres的創建這兩個屬性(列)的唯一索引。 訪問或加入freelancer_id是快速的,因爲它是第一個在索引中。訪問或加入freelancer_by_niche.niche_id將會很慢(全表掃描freelancer_by_niche)。

因此,您應該在此表freelancer_by_niche的第二部分niche_id上創建一個INDEX。

CREATE INDEX ON freelancer_by_niche (niche_id) ; 

然後加入到上niche_id此表也將更快,因爲它們是由一個指數加速。索引使查詢更快(通常)。

摘要

你有一個很好的規範化的數據庫架構!這很好。但是可以做出很小的改進(見上文)。

+0

我想給一個簡單的解決方案。他是一名初學者。當然,有更好的方法來做到這一點,但它們更復雜。 –

+0

這看起來像一個很好的答案。不過,我想補充一點,儘管向人們展示投票/接受系統是如何工作的,但在評論中,如果您認爲他們不知道如何使用投票/接受系統,我認爲我們通常不鼓勵明確要求投票自己投票。我們喜歡在這裏投票合理有機。 – halfer