多表、多行SQL选择

多表、多行SQL选择,sql,postgresql,Sql,Postgresql,根据下面的模式,我如何列出自由职业者的所有信息?包括利基、语言、市场等。我面临的问题是,每个自由职业者可以为每个表格输入多个条目。那么,我该怎么做呢?是否可能使用SQL,或者我是否需要使用我的主要语言golang CREATE TABLE freelancer ( freelancer_id SERIAL PRIMARY KEY, ip inet NOT NULL, username VARCHAR(20

根据下面的模式,我如何列出自由职业者的所有信息?包括利基、语言、市场等。我面临的问题是,每个自由职业者可以为每个表格输入多个条目。那么,我该怎么做呢?是否可能使用SQL,或者我是否需要使用我的主要语言golang

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)

);
如果您想从连接表中丢失不必要的属性,比如freeloper\u by\u格式,那么您可以这样做

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更改为just market,那么您可以使用

SELECT a.ip, ... ,  
       d.market_name "market", e.format_name AS "format", ...  
FROM ...  
评论 例如,在你的加入表中,自由职业者的身份没有唯一的限制,这意味着你可以在多个市场拥有相同的自由职业者,这是可以的,而且可能是有意的

但是你也没有对自由职业者id和利基id这两个属性的唯一限制,这意味着每个自由职业者都可能多次处于同一利基。乔从事电子行业。三次。 你可以通过让自由职业者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
使用

SELECT * FROM freelancer_by_lang;
现在尝试选择*从自由职业者内部连接。。。事情 如果它仍然运行快,然后做所有的插入到自由职业者的利基。。。一次又一次,直到永远无法计算结果。 或者,您可以使用DISTINCT删除重复项

创建唯一的数据联接表

可以在联接表中防止重复。 删除id串行主键并用多属性主键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)
);
将此应用于所有联接表。 主键自由职业者id,利基id将创建一个唯一的索引。 这样,您就不能插入重复的数据。请尝试上面的插入,将拒绝该数据,因为该信息已经存在一次。添加其他时间不会添加更多信息,并且会使查询运行时慢得多

联接表其他部分上的非唯一索引 Postgres使用主键自由职业者id、利基id在这两个属性列上创建一个唯一的索引。 自由职业者的访问或加入速度很快,因为它是索引中的第一个。通过利基访问或加入自由职业者。利基id将在自由职业者利基上进行缓慢的全表扫描

因此,您也应该在这个表中的第二部分niche_id上创建一个索引

然后在niche_id上加入这个表也会更快,因为它们会被索引加速。索引通常会加快查询速度

总结


您有一个非常好的规范化数据库模式!非常好。但是可以做一些小的改进,请参见上文。

从我读到的内容来看,在您的问题中,您在连接表格时遇到了问题?添加了一个答案和一条重要的备注。Blake,我们可以看看您尝试了什么吗?目前,这是相当宽泛的,因为在这个问题上没有尝试或研究。顺便说一句,你接受答案会得到分数。我试图给出一个简单的解决方案。他是个初学者。当然有更好的方法可以做到这一点,但它们更复杂。这看起来是一个很好的答案。然而,我想补充一点,虽然在评论中向人们展示投票/接受系统的工作原理是可以的,但如果你认为他们不知道如何使用它,我认为我们通常不鼓励在帖子中明确要求投票。我们喜欢在这里投票是合理的有机。
SELECT * FROM freelancer_by_lang;
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)
);
CREATE INDEX ON freelancer_by_niche (niche_id) ;