2017-05-08 64 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