12

次のデータを含む 3 つのテーブルがあります。

接続と呼ばれる最初のテーブルconnections.username1は、connections.username2フォローする人であり、フォローされる人です。

次の行があります。

connections.username1 | connections.username2
      mikha           |          guy
      guy             |          maricela
      maricela        |          guy

質問と呼ばれる 2 番目のテーブル。と呼ばれる質問者用の列と、 とquestions.asker_username呼ばれる質問を受ける人用の列がありますquestions.target_username。質問者が「sys.tem」と呼ばれ、ターゲットが「every.one」と呼ばれる場合、それはグローバルな質問と見なされ、すべてのメンバーが回答できます。

匿名ユーザーが尋ねることができ、その IP は として記録されますasker_username

次の行があります。

questions.id | questions.asker_username | questions.target_username | questions.question
  1          |      mikha               |       guy                 | what's your name?                             
  2          |      mikha               |       maricela            | What's your age?
  3          |      guy                 |       mikha               | what's your name?
  4          |      maricela            |       guy                 | favorite food?
  5          |      xx.xx.xxx.xx        |       mikha               | favorite pet?
  6          |      xx.xx.xxx.xx        |       guy                 | first name?
  7          |      xx.xx.xxx.xx        |       maricela            | first name?   
  8          |      sys.tem             |       every.one           | what's ur name?
  9          |      sys.tem             |       every.one           | favorite movie?  
 10          |      sys.tem             |       every.one           | favorite game? 

3 番目の表は回答と呼ばれます。Answers テーブルの ID は質問 ID と同じです。このテーブルには、ID、ユーザー名、および回答の列があります。

answers.id  |  answers.username | answers.answer
   1        |       guy         | my name is guy
   2        |     maricela      | my name is maricela
   3        |       mikha       | my name is mikha
   4        |       guy         | pizza        
   8        |       guy         | guy is my name
   8        |       maricela    | maricela is my name   
   9        |       maricela    | avatar

「mikha」と彼がフォローしている人に関する次の条件を組み合わせたクエリが必要です。

1) questions.asker_username「ミカ」ではありません

2) questions.target_username「ミカ」または彼がフォローしているユーザーのいずれかです。

3) questions.target_username「every.one」に等しく、「mikha」と答えた場合、質問を表示します。

4) questions.target_username「every.one」に等しく、「mikha」がフォローしている人のいずれかが回答した場合、質問とその回答を示します。mikha さんがフォローしているユーザーからの回答がない場合は、質問を表示しません。

5) questions.target_username「every.one」に等しく、誰もまったく答えない場合は、質問を 1 回表示します。

6) questions.target_username「every.one」に等しく、「mikha」から回答がなく、フォローしているユーザーからも回答がない場合は、質問を 1 回だけ表示します。

次のクエリを使用します。

SELECT questions.id,answers.id,questions.asker_username,questions.target_username,
    answers.username,questions.question,answers.answer 
FROM questions 
    LEFT JOIN answers ON (questions.id = answers.id) 
    LEFT JOIN connections ON connections.username1 = 'mikha' 
        AND (questions.target_username = connections.username2 
            OR questions.asker_username = connections.username2 
            OR connections.username2 = answers.username) 
WHERE questions.asker_username <> 'mikha' 
    AND (questions.target_username = 'mikha' 
        OR questions.target_username = connections.username2 
        OR (questions.target_username = 'every.one' 
            AND (answers.username = 'mikha' 
                OR answers.username = connections.username2
                OR answers.username IS NULL)
            )
        ) 
GROUP BY questions.id,answers.username

私が期待する結果:

questions.id | answers.id | questions.asker_username | questions.target_username | answers.username | questions.question | answers.answer
    3        |      3     |        guy               |          mikha            |    mikha         | what's your name?  | my name is mikha
    4        |      4     |        maricela          |          guy              |    guy           | favorite food?     | pizza
    5        |      5     |        xx.xx.xxx.xx      |          mikha            |    NULL          | favorite pet?      | NULL
    6        |      6     |        xx.xx.xxx.xx      |          guy              |    NULL          | first name?        | NULL        
    8        |      8     |        sys.tem           |         every.one         |    NULL          | what's ur name?    | NULL 
    8        |      8     |        sys.tem           |         every.one         |    guy           | what's ur name?    | guy is my name
    9        |      9     |        sys.tem           |         every.one         |    NULL          | favorite movie?    | NULL       
    10       |      10    |        sys.tem           |         every.one         |    NULL          | favorite game?     | NULL 

私が実際に得た結果:

 questions.id | answers.id | questions.asker_username | questions.target_username | answers.username | questions.question | answers.answer
    3        |      3     |        guy               |          mikha            |    mikha         | what's your name?  | my name is mikha
    4        |      4     |        maricela          |          guy              |    guy           | favorite food?     | pizza
    5        |      5     |        xx.xx.xxx.xx      |          mikha            |    NULL          | favorite pet?      | NULL
    6        |      6     |        xx.xx.xxx.xx      |          guy              |    NULL          | first name?        | NULL        
    8        |      8     |        sys.tem           |         every.one         |    guy           | what's ur name?    | guy is my name           
    10       |      10    |        sys.tem           |         every.one         |    NULL          | favorite game?     | NULL 

http://sqlfiddle.com/#!2/29929e/1でスキームを作成して、実際に得た結果を示しました

ありがとう :)

4

3 に答える 3

5

OK、最も単純なものから始めましょう (あなたの最初のルール):

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id  
WHERE q.asker_username <> 'mikha' 
GROUP BY q.id,a.username

次に、2 番目のルールを追加しましょう - さらに複雑になります...

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id 
WHERE q.asker_username <> 'mikha' 
    AND q.target_username = 'mikha' 
        OR q.target_username IN (
            SELECT username2 
            FROM connections 
            WHERE username1 = 'mikha'
        )
GROUP BY q.id,a.username

次に、3 番目のルール (mikha が回答したすべてのユーザー向け):

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id 
WHERE q.asker_username <> 'mikha' 
    AND q.target_username = 'mikha' 
        OR q.target_username IN (
            SELECT username2 
            FROM connections 
            WHERE username1 = 'mikha'
        )
        OR (q.target_username = 'every.one' AND a.username = 'mikha')
GROUP BY q.id,a.username

次に、4 番目のルールについて説明します。

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id 
WHERE q.asker_username <> 'mikha' 
    AND q.target_username = 'mikha' 
        OR q.target_username IN (
            SELECT username2 
            FROM connections 
            WHERE username1 = 'mikha'
        )
        OR (q.target_username = 'every.one' AND a.username = 'mikha')
        OR (q.target_username = 'every.one' AND a.username IN (
            SELECT username2 
            FROM connections 
                INNER JOIN answers ON answers.username = connections.username2
                    AND answers.answers IS NOT NULL
            WHERE username1 = 'mikha'
        ))
GROUP BY q.id,a.username

第 5 の規則 (イエス!):

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id 
WHERE q.asker_username <> 'mikha' 
    AND q.target_username = 'mikha' 
        OR q.target_username IN (
            SELECT username2 
            FROM connections 
            WHERE username1 = 'mikha'
        )
        OR (q.target_username = 'every.one' AND a.username = 'mikha')
        OR (q.target_username = 'every.one' AND a.username IN (
            SELECT username2 
            FROM connections 
                INNER JOIN answers ON answers.username = connections.username2
                    AND answers.answers IS NOT NULL
            WHERE username1 = 'mikha'
        ))
        OR (q.target_username = 'every.one' AND a.answer IS NULL)
GROUP BY q.id,a.username

そして最後のものについて:

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id 
WHERE q.asker_username <> 'mikha' 
    AND q.target_username = 'mikha' 
        OR q.target_username IN (
            SELECT username2 
            FROM connections 
            WHERE username1 = 'mikha'
        )
        OR (q.target_username = 'every.one' AND a.username = 'mikha')
        OR (q.target_username = 'every.one' AND a.username IN (
            SELECT username2 
            FROM connections 
                INNER JOIN answers ON answers.username = connections.username2
                    AND answers.answers IS NOT NULL
            WHERE username1 = 'mikha'
        ))
        OR (q.target_username = 'every.one' AND a.answer IS NULL)
        OR (q.target_username = 'every.one' AND a.username NOT IN (
            SELECT username2 
            FROM connections 
                INNER JOIN answers ON answers.username = connections.username2
                    AND answers.answers IS NOT NULL
            WHERE username1 = 'mikha'
        ))
GROUP BY q.id,a.username

ルール 4 とルール 6 は互いに反するものであり (矛盾していると言えます)、1 つのクエリで使用すると、省略した場合と同じ効果があると思います...

どのクエリもテストしていませんが、うまくいくと思います。

于 2012-12-14T13:08:31.987 に答える
2

問題は、状況によっては、一致する回答が 1 つしかない場合に、質問を 2 回表示したい場合です。私は引用します:

だから、「mikha」が回答されたかどうかにかかわらず一度だけ表示し、「mikha」がフォローしている人のいずれかが回答するたびにもう一度表示したいと思います

この重複は物事をかなり難しくします。

私はそれを a で解決しようとしましたが、UNIONうまくいくようです。しかし、私はまだあなたの要件を完全には理解していません...

とにかく、ここに行きます:

select * from
(
  select
    q.id as q_id, a.id as a_id, q.asker_username,
    q.target_username, a.username, q.question, a.answer
  from
    questions q
    left outer join answers a on q.id = a.id
  where
    q.asker_username <> 'mikha' 
    and
    (
      q.target_username = 'mikha'
      or q.target_username in
         (select username2 from connections where username1 = 'mikha')
      or
      (
        q.target_username = 'every.one'
        and
        (
          a.username = 'mikha'
          or a.username in
             (select username2 from connections where username1 = 'mikha')
          or a.id is null
        )
      )
    )
  union
  select
    q.id as q_id, NULL as a_id, q.asker_username,
    q.target_username, NULL, q.question, NULL
  from
    questions q
  where
    q.asker_username <> 'mikha' 
    and q.target_username = 'every.one'
    and not exists (select id
                    from answers
                    where
                      id = q.id
                      and username = 'mikha'
                    )
) r
order by q_id;

ライブでテスト:
質問 8 に対する mikha の回答あり 質問 8
に対する mikha の回答なし

于 2012-12-14T14:08:31.083 に答える
0

出発点の主な問題の 1 つは、接続テーブルに 2 回参加する必要があることです。1 回は回答用、もう 1 回は質問用です。

以下のコードは、実行内容に関するインライン コメントを提供します。また、比較には数値IDフィールドの方が適していることを示唆する他の回答にも同意します-また、回答テーブルに一意のrowidフィールドを配置することをお勧めします(さらに、一意のフィールドに変更idquestion_idてから作成することをお勧めしidます.

SELECT DISTINCT q.id,a.id,q.asker_username,q.target_username,a.username,q.question,a.answer
FROM questions q
  /* Answers */
  LEFT JOIN answers a ON (q.id=a.id)
  /* connection entries where the person being followed is the target */
  LEFT JOIN (SELECT username2 FROM connections WHERE username1='mikha') c_q
    ON c_q.username2=q.target_username
  /* connection entries where the person being followed answered the question */
  LEFT JOIN (SELECT username2 FROM connections WHERE username1='mikha') c_a
    ON c_a.username2=a.username 
  /* Own answers */
  LEFT JOIN (SELECT id FROM answers WHERE username='mikha') a_own 
    ON (q.id=a_own.id) 
  WHERE 
  /* Asker not mikha, target is mikha or followed user - rules 1,2 */
  (q.asker_username <> 'mikha'
  AND (q.target_username='mikha' OR c_q.username2 IS NOT NULL))
  OR
  /* sys.tem/every.one, answered by mikha - rule 3 */
  (q.target_username='every.one' AND a.username='mikha')
  OR
  /* Rules 4, 5 & 6 combine to give "show the answer at least once, and once for every followed user who answered" - here we select any every.one messages where mikha didn't answer and nor did the people he follows */
  (q.target_username='every.one' AND a_own.id IS NULL AND c_a.username2 IS NULL);

質問 8 では 2 つの行が表示されませんが、なぜそれが必要なのかがわかりませんでした。問題は、どのルールが追加的で、どれが組み合わせ的であるかが明確でないことです。行を表示する別の理由を提供するだけでなく、どのルールが行を「追加」する必要があるかを説明できれば、質問 8 の追加の行も取得できるかもしれません。

于 2012-12-14T13:46:23.183 に答える