0

我有一个用户表、一个帖子表、一个私有表和一个 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 已登录,则 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 的第二个 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 的用户应该只看到公开的帖子(私有 0)或(私有 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)

在您的第二个查询中,正在计算以下帖子(有原因):

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)'

在您的第三个查询中,正在计算以下帖子(有原因):

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. p.user_id='2'从 `CASE1 语句中删除

    无论如何,这始终是正确的,因为您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如果您正确分组聚合函数,您也不应该需要。每个用户只应返回一行。

于 2013-02-09T19:16:49.103 回答