2012-02-20 18 views
1

昨日、1つのクエリを数時間以上テストしましたが、成功しませんでした。これらは、3つの表のとおりです。SQL 3つのテーブルで結合する

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 

問題は、これが私に正しい情報を与えないということです。 DBには2つの反応しかありませんが、8つの陽性反応のような値を返します。

私はそれがGROUP BY p.id、r.idと関係があると思いますが、私はそれを試みましたが、うまくいかなかったのです...誰かが私を教えてくれましたか?

ありがとうございます!

+1

?サブクエリを使用する必要があります。サブクエリを使用すると、ユーザが投稿を別々に投稿する必要があります。現在、投稿と反応が交差しているため、重複が多く発生します。 – GarethD

+0

同意後にカンマが不足しているようです。 – xQbert

+0

ええ、私は私が使用した実際のコードではなく、私のブラウザにこれを入力していました。 – Diederik

答えて

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 
+1

これはうまくいきますが、4つの相関サブクエリは、通常、相関のないサブクエリの結合に対してよりよくリファクタリングされます。 – MatBailie

+0

@Dems適切なオプティマイザを備えたDBMSにはありません。相関サブクエリはNESTED LOOPを必ずしも意味するものではなく、興味深いことに、NESTED LOOPが常に最速の方法であるとは限りません。実際に**測定**せずにこの種の毛布の声明を作ることは正当化されません。 –

+0

これは本当に私のために働いた。 Demsの解決策は私にエラーを与えました、私はそれを解決しようとします。 – Diederik

2

それはグループ化されません、あなたの加入は、複数のレコードに参加している他の内の単一のレコードに、一つのテーブルを形成します。これが重複の原因です。

たとえば、ユーザーテーブルの1つのエントリでは、反応で3つの応答があり、投稿で3つの応答があります。そのユーザの反応の全てがそのユーザーの投稿のすべてに参加しているので、あなたのクエリが

...これはあなたが記事とは別に反応を集約する必要があることを意味
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 

...、9つのレコードを返します
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 
+0

いくつかの構文エラーがありましたが、それらを修正しても、私が望む結果が得られませんでした。数字はオフです。ブランコの解決策はうまくいくので、私はその問題に取り組めると思う。あなたの助けをありがとう!:) – Diederik

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 
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 
何RDBMS
関連する問題