0

私が持っているのは、usersテーブル、postsテーブル、privateテーブル、およびuser_statsテーブルです。

users                     
user_id |  user_name
--------------------
   1    |    tony
   2    |    steph
   3    |    lizzy
   4    |    adam

posts
post_id   user_id     sugg_by   private (0 is public, 1 is private to authorized users)
-----------------------------------------------------
   1         1           2         0
   2         2           2         1
   3         2           2         1            
   4         2           4         1
   5         2           2         1
   6         2           3         0

private
private_id   post_id   authorized_user_id
-----------------------------------------------
    1           2               4
    2           2               3
    3           4               4
    4           5               1
    5           5               3

user_stats                     
user_id  orig_posts_count(user_id=sugg_by in posts)  sugg_posts_count(user_id<>sugg_by in posts) 
-----------------------------------------------------------------------------------------------------
   1             0                                          1
   2             3                                          2
   3             0                                          0
   4             0                                          0

私が抱えている問題は、このクエリにあります。この例では、「4」は$ logged_in_id adamであり、「2」はstephでカウントしている投稿のuser_idです。stephがlogged_inの場合、COUNTは実行されず、「posterview」が表示されます。これは機能します。他のログインユーザーまたはログアウトしたユーザーに戻ると、問題が発生します。したがって、アダム '4'の場合:

SELECT u.user_id, us.orig_posts_count, us.sugg_posts_count,
IF(us.user_id='4', 'posterview',
COUNT(case when ISNULL(pv.post_id) AND p.private='1' AND p.user_id='2' AND p.sugg_by='2' then null else 1 end)
) as display_orig_posts_count,
IF(us.user_id='4', 'posterview',
COUNT(case when ISNULL(pv.post_id) AND p.private='1' AND p.user_id='2' AND p.sugg_by<>'2' then null else 1 end)
) as display_sugg_posts_count
FROM users u 
JOIN user_stats us ON u.user_id=us.user_id 
JOIN posts p ON p.user_id=us.user_id
LEFT JOIN private pv on pv.post_id = p.post_id AND pv.authorized_user_id='4' 
WHERE u.user_id='2' LIMIT 1

出力は次のようになります。

user_id  orig_posts_count  sugg_posts_count  display_orig_posts_count  display_sugg_posts_count
   2            3                  2                    1                          2

ただし、次のように出力されます。

user_id  orig_posts_count  sugg_posts_count  display_orig_posts_count  display_sugg_posts_count
   2            3                  2                    3                          5

その理由はJOIN posts p ON p.user_id=us.user_id

これをJOIN posts p ON p.user_id=us.user_id AND p.sugg_by='2'(display_orig_posts_countの最初のCOUNTと一致する)に変換すると、display_orig_posts_countは1で正しいですが、display_sugg_posts_countは3で正しくありません。正しいdisplay_orig_posts_countと誤ったdisplay_sugg_posts_countを取得します。次のように出力します:

user_id  orig_posts_count  sugg_posts_count  display_orig_posts_count  display_sugg_posts_count
   2            3                  2                    1                          3

これをJOIN posts p ON p.user_id=us.user_id AND p.sugg_by<>'2'(display_sugg_posts_countの2番目のCOUNTと一致する)に変換すると、display_orig_posts_countは2になりますが、これは正しくありませんが、display_sugg_posts_countは2で正しいです。出力は次のとおりです。

user_id  orig_posts_count  sugg_posts_count  display_orig_posts_count  display_sugg_posts_count
   2            3                  2                    2                          2

基本的に、stephが'posterview'を返す必要がある場合にログインしたユーザーですが、COUNTを使用する他のユーザーは、パブリック(private 0)または(private 1)の一部である場合にのみ、投稿を表示してからカウントする必要がありますCOUNT句の条件に基づいて、指定された正しい出力を取得します。私はこれに何時間も立ち往生しています。クエリを正しく機能させる方法はありますか?注:出力例ごとにフィドルが含まれています。

4

1 に答える 1

3

クエリを次のように変更します。

  SELECT u.user_id, us.orig_posts_count, us.sugg_posts_count,
    IF(us.user_id='4', 'posterview',
      COUNT(CASE
        WHEN p.sugg_by='2' AND (p.private='0' OR pv.post_id IS NOT NULL)
        THEN 1
        ELSE NULL
      END)) AS display_orig_posts_count,
    IF(us.user_id='4', 'posterview',
      COUNT(CASE
        WHEN p.sugg_by<>'2' AND (p.private='0' OR pv.post_id IS NOT NULL)
        THEN 1
        ELSE NULL
      END)) AS display_sugg_posts_count
    FROM users AS u
         JOIN user_stats AS us ON u.user_id=us.user_id
         JOIN posts AS p ON p.user_id=us.user_id
         LEFT JOIN private AS pv ON pv.post_id=p.post_id AND pv.authorized_user_id='4'
   WHERE u.user_id='2'
GROUP BY u.user_id, us.orig_posts_count, us.sugg_posts_count

詳細な説明

最初のクエリでは、次の投稿がカウントされています(理由付き)。

display_orig_posts_count = 3:
  post_id=2: pv.post_id is not null (fails ISNULL() check)
  post_id=4: pv.post_id is not null (fails ISNULL() check)
  post_id=6: p.private='0'          (fails p.private='1' check)

display_sugg_posts_count = 5:
  post_id=2: pv.post_id is not null (fails ISNULL() check)
  post_id=3: p.sugg_by='2'          (fails p.sugg_by<>'2' check)
  post_id=4: pv.post_id is not null (fails ISNULL() check)
  post_id=5: p.sugg_by='2'          (fails p.sugg_by<>'2' check)
  post_id=6: p.private='0'          (fails p.private='1' check)

2番目のクエリでは、次の投稿がカウントされています(理由付き)。

display_orig_posts_count = 1:
  post_id=2: pv.post_id is not null (fails ISNULL() check)

display_sugg_posts_count = 3:
  post_id=2: pv.post_id is not null (fails ISNULL() check)
  post_id=3: p.sugg_by='2'          (fails p.sugg_by<>'2' check)
  post_id=5: p.sugg_by='2'          (fails p.sugg_by<>'2' check)'

3番目のクエリでは、次の投稿がカウントされています(理由付き)。

display_orig_posts_count = 2:
  post_id=4: pv.post_id is not null (fails ISNULL() check)
  post_id=6: p.private='0'          (fails p.private='1' check)

display_sugg_posts_count = 2:
  post_id=4: pv.post_id is not null (fails ISNULL() check)
  post_id=6: p.private='0'          (fails p.private='1' check)

何を数えたいですか:

display_orig_posts_count = 1:
  post_id=2: because p.sugg_by=2, p.private=1 AND (is_authorized)

display_sugg_posts_count = 3:
  post_id=4: because p.sugg_by<>'2', p.private=1 AND (is_authorized)
  post_id=6: because p.sugg_by<>'2', p.private=0

それでは、これをクリーンアップしましょう。

  1. ` CASE1p.user_id='2'ステートメントから削除します

    とにかく、これは常に当てはまります。ステートメントuser_id='2'によって、投稿をでそれらの投稿のみに制限しているからです。JOIN

  2. 肯定的なチェックを使用する

    の場合、display_orig_posts_count特定のものが必要です。不要なものを除外するのではなく、必要なものを明示的に探しましょ

     COUNT(CASE
       WHEN p.sugg_by='2' AND (p.private='0' OR pv.post_id IS NOT NULL)
       THEN 1
       ELSE NULL
     )
    

    の場合、display_sugg_posts_countそれらを明示的に探してみましょう。

     COUNT(CASE
       WHEN p.sugg_by<>'2' AND (p.private='0' OR pv.post_id IS NOT NULL)
       THEN 1
       ELSE NULL
     )
    
  3. GROUP BY集計関数を使用するときに使用します

    LIMIT 1集約された関数を適切にグループ化する場合も、必要ありません。ユーザーごとに1行だけが返される必要があります。

于 2013-02-09T19:16:49.103 に答える