从多个JOINS获取所有数据

时间:2012-11-21 17:17:02

标签: php mysql relational-database foreign-key-relationship

我在这里要做的是让所有申请某项工作或通过选择工作然后选择要搜索的标签来申请某项工作的申请人。这是我正在使用的sql语句。

SELECT ap.user_id, ap.job_id as jobId, date(app_date) AS appDate, count(*) AS `count`   ,jt.name AS title, a.*, ap.app_id
FROM applications ap
LEFT JOIN jobs j ON ap.job_id = j.job_id
LEFT JOIN job_titles jt ON jt.name = j.title
LEFT JOIN applicants a ON a.applicant_id = ap.user_id
LEFT JOIN applicant_tags at ON at.applicant_id = ap.user_id
LEFT JOIN tags t ON t.id = at.tag_id
WHERE ap.favorite = 1
AND LOWER(jt.name) = LOWER('fisherman')
AND (LOWER(t.name) = LOWER('confident')
OR LOWER(t.name) = LOWER('hard worker'))
GROUP BY ap.app_id
HAVING `count` = '2'
ORDER BY jt.name

我的问题是,我只收到已申请该职位的申请人,而不是那些已被标记为该类职位的申请人。作业名称本身不会存储为标签,而是通过applicant_tags表链接到每个申请人,如下所示:

applicant_id | tag_id | job_id
34                0        4
34                4        0
34                0        5
32                7        0

applicant_id通过应用程序user_id链接到应用程序,通过标签id链接到tag_id,通过job_titles id链接到job_id。 tags表和job_titles表中只有id和name。

这是标签表:

id | tag_id

job_titles表:

id | name

申请人拥有申请人的所有个人信息(电子邮件,电话号码)以及用作外键的applicant_id。

应用程序和作业列出的信息太多,实际上只使用了几列。

申请表

app_id | user_id | job_id | app_date | favorites .....

工作表

job_id | title | location | jobtype .....

申请人的tag_id如果有job_id则为0,反之亦然。标签名称和作业名称不会以逗号分隔值的形式存储,而是作为一行中的单个值存储,并通过其applicant_id链接到每个申请人。作业中的job_id是所申请作业的ID,而不是作业名称。每个申请人都可以拥有多个与之关联的标签以及与之相关的多个职位名称。标签语句LOWER(t.name)= LOWER(标签名称)是根据搜索中使用的标签数量添加的。我从申请人处获得了所有信息,因为该信息以及应用程序中调用的内容将显示在页面上。

应用程序ap通过ap.job_id链接到jobs,app_tags链接到ap.applicant_id = at.applicant_id,申请者通过ap.applicant_id链接到a.applicant_id。

job_titles jt通过jt.name = j.title链接到作业j,通过j.id = at.job_id链接到applicant_tags

标签t通过t.id = at.tag_id

链接到applicant_tags

我也不能使用聚合表。

那么如何才能将链接到作业名称的应用程序从job表到job_titles表,而是从applicant_tags表到job_titles表?

- 编辑

重构我的sql语句后,我可以将它显示在显示所有申请人但没有标签的地方,如果我尝试搜索任何标签,则不会返回任何结果。

SELECT ap.user_id, jt.id as jobId, date(app_date) AS appDate, jt.name AS title,   count(*) AS `count`, at.*, a.*, ap.app_id, t.*    
FROM applications ap                                 
INNER JOIN applicants a ON ap.user_id = a.applicant_id
LEFT JOIN applicant_tags at ON at.applicant_id = a.applicant_id
LEFT JOIN tags t ON at.tag_id = t.id
LEFT JOIN job_titles jt ON at.job_id = jt.id
WHERE ap.favorite = '1'
AND LOWER(jt.name) = LOWER('fisherman')
GROUP BY ap.app_id
HAVING `count` = '1'
ORDER BY jt.name

2 个答案:

答案 0 :(得分:0)

我会看看嵌套查询,在另一个注意事项....这可以在下面找到... http://www.felixgers.de/teaching/sql/sql_nested_queries.html

对于此查询,如果将所有申请人信息整理到单个聚合表中会更容易。然后将作业ID的东西加入到另一个表中,或者使用原始的,适当地添加索引,这样它就不会超时,并且繁荣......更容易。

SELECT ap.user_id, ap.job_id as jobId, date(app_date) AS appDate, count(*) AS `count` ,jt.name AS title, `a.*` -- a.* is this necessary? It would help if you were explicit
FROM applications ap
LEFT JOIN jobs j ON ap.job_id = j.job_id --take all items from applications and puta  jobid to them
LEFT JOIN job_titles jt ON jt.name = j.title -- now you are trying to add a title to job from ANOTHER table while retaining all records from applications
LEFT JOIN applicants a ON a.applicant_id = ap.user_id --then you want the applicant that matches the criteria to each application record
LEFT JOIN applicant_tags at ON at.applicant_id = ap.user_id
LEFT JOIN tags t ON t.id = at.tag_id
WHERE ap.favorite = 1
AND LOWER(jt.name) = LOWER('fisherman')
AND (LOWER(t.name) = LOWER('confident')
OR LOWER(t.name) = LOWER('hard worker')) 
GROUP BY ap.app_id -- how are you grouping by something that is not being called?
HAVING `count` = '2' -- They need to have two records, does not matter if they are the same
ORDER BY jt.name -- This is fine

好的,除了我的评论,这实际上是合法的。然而,我会创建一个申请人信息的聚合表,然后在该表上进行单个连接,以使事情变得更容易

看起来你正在使用的表是:

应用 加入 申请人的标准

内连接这些表

Applicants_tags将标签加入sample_tags 标签 工作 - 加入这个 job_titles for jobs表

答案 1 :(得分:0)

我发现了怎么做。我不得不使用带有IN子句的子查询:

SELECT ap.user_id, jt.id as jobId, date(app_date) AS appDate, jt.name AS title, count(*) AS `count`, at.*, a.*,ap.app_id
FROM applications ap
LEFT JOIN jobs j ON ap.job_id = j.job_id
LEFT JOIN job_titles jt ON jt.name = j.title
LEFT JOIN applicants a ON a.applicant_id = ap.user_id
LEFT JOIN applicant_tags at ON at.applicant_id = ap.user_id
LEFT JOIN tags t ON t.id = at.tag_id
WHERE ap.favorite = 1
AND (
    LOWER(jt.name) = LOWER('fisherman') OR 'fisherman' IN(SELECT jt.name FROM applicant_tags at 
    LEFT JOIN job_titles jt ON at.job_id = jt.id 
    WHERE at.applicant_id = a.applicant_id))
AND (LOWER(t.name) = LOWER('confident')
    OR LOWER(t.name) = LOWER('hard worker'))
GROUP BY ap.app_id
HAVING `count` = '2'
ORDER BY jt.name

感谢大家的帮助!