SQL加入三个表

时间:2012-02-20 13:06:49

标签: php sql join

昨天我一直在测试一个查询超过几小时和几小时,但我从未成功过。这是三个表:

USERS:
#### id: 1 ##### name: Admin ##### Hometown: The Hague

POSTS:
#### id: 1 ##### userid: 1 ##### title: Test I ##### opinion: agree
#### id: 2 ##### userid: 1 ##### title: Nope.. ##### opinion: disagree

REACTIONS:
#### id: 1 ##### userid: 1 ##### opinion: agree
#### id: 2 ##### userid: 1 ##### opinion: disagree

这就是我想要的: 我想要用户的基本信息(姓名,家乡等),我想要多少赞美(后意见:同意),多少投诉(意见后:不同意),多少积极反应(反应 - 意见) :同意)和这个人发布了多少负面反应(反应 - 意见:不同意)。

这是我现在使用的查询:

    SELECT
        u.name, u.hometown,

        SUM(IF(r.opinion="disagree",1,0)) AS agrees
        SUM(IF(r.opinion="disagree",1,0)) AS disagrees,

        SUM(IF(p.opinion="agree",1,0)) AS compliments,
        SUM(IF(p.opinion="disagree",1,0)) AS complaints

    FROM
        users AS u

    LEFT JOIN
        reactions AS r
    ON
        r.userid = u.id

    LEFT JOIN
        posts AS p
    ON
        p.userid = u.id

    WHERE
        u.id = 1

问题是这不能给我正确的信息。它会返回8个正反应之类的值,尽管DB中只有两个反应。

我认为它与GROUP BY p.id,r.id有关但我尝试了它并且它不起作用...有人可以启发我吗?

提前致谢!

4 个答案:

答案 0 :(得分:2)

它不会是分组,您的联接会将多个记录从一个表连接到另一个表中的单个记录。这导致你的重复。

例如,对于用户表中的单个条目,您可能在响应中有3个响应,在帖子中可能有3个响应。您的查询返回9条记录,因为该用户的所有反应都会加入到该用户的所有帖子中...

userid | reaction_id | post_id
  1           1           1
  1           1           2
  1           1           3
  1           2           1
  1           2           2
  1           2           3
  1           3           1
  1           3           2
  1           3           3

这意味着您需要将这些反应与帖子分开汇总......

SELECT
    u.name, u.hometown,

    r.agrees
    r.disagrees,

    p.compliments,
    p.complaints

FROM
    users AS u
LEFT JOIN
(
  SELECT
    userid,
    SUM(IF(r.opinion="agree",1,0)) AS agrees
    SUM(IF(r.opinion="disagree",1,0)) AS disagrees,
  FROM
    reactions
  GROUP BY
    userrid
)
  AS r
    ON r.userid = u.id
LEFT JOIN
(
  SELECT
    userid,
    SUM(IF(p.opinion="agree",1,0)) AS compliments,
    SUM(IF(p.opinion="disagree",1,0)) AS complaints
  FROM
    posts
  GROUP BY
    userid
)
  AS p
    ON p.userid = u.id
WHERE
    u.id = 1

答案 1 :(得分:0)

根据您的DBMS,您可以这样做:

SELECT
    *,
    (SELECT COUNT(*) FROM POSTS WHERE POSTS.userid = USERS.id and opinion = 'agree') compliments,
    (SELECT COUNT(*) FROM POSTS WHERE POSTS.userid = USERS.id and opinion = 'disagree') complaints,
    (SELECT COUNT(*) FROM REACTIONS WHERE REACTIONS.userid = USERS.id and opinion = 'agree') positive_reactions,
    (SELECT COUNT(*) FROM REACTIONS WHERE REACTIONS.userid = USERS.id and opinion = 'disagree') negative_reactions
FROM USERS

答案 2 :(得分:0)

怎么样?

select id, name, hometown, sum(agrees) agrees, sum(disagrees) disagrees,
  sum(compliments) compliments, sum(complaints) complaints
from (
  select u.id, u.name, u.hometown,
    if(p.opinion = 'agree', 1, 0) agrees,
    if(p.opinion = 'disagree', 1, 0) disagrees,
    0 compliments, 0 complaints
  from users u
  left join posts p on u.id = p.userid
  union all
  select u.id, u.name, u.hometown,
    0, 0,
    if(r.opinion = 'agree', 1, 0),
    if(r.opinion = 'disagree', 1, 0)
  from users u
  left join reactions r on u.id = r.userid
) as S
group by id, name, hometown

答案 3 :(得分:0)

select users.name, users.hometown, myPosts.compliments, myPosts.complaints,        myReaction.agrees, myReaction.disagrees
from Users users
LEFT JOIN
(
    select post.userid as userid
         , SUM(CASE WHEN post.opinion = 'agree' THEN 1 END) as compliments
         , SUM(CASE WHEN post.opinion = 'disagree' THEN 1 END) as complaints
    from Posts post
    group by post.userid
) as myPosts
on users.id = myPosts.userid
LEFT JOIN
(
    select reaction.userid as userid
     , SUM(CASE WHEN reaction.opinion = 'agree' THEN 1 END) as agrees
     , SUM(CASE WHEN reaction.opinion = 'disagree' THEN 1 END) as disagrees
    from Reaction reaction
    group by reaction.userid
) as myReaction
on users.id = myReaction.userid