我有一个用户表,一个帖子表,一个私有表和一个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
然而outputs为:
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。 Outputs as:
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. Outputs处正确为:
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子句中的条件进行计数,以获得所述的正确输出。我已经坚持了几个小时。知道如何让查询正常工作吗? 注意:每个示例输出都包含小提琴。
答案 0 :(得分: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
所以让我们清理一下:
从`CASE1语句中删除p.user_id='2'
无论如何,这始终是正确的,因为您通过user_id='2'
语句将帖子限制为只有JOIN
的帖子。
使用肯定性支票
如果是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
)
使用汇总功能时使用GROUP BY
如果您正确地对聚合函数进行分组,则您也不需要LIMIT 1
。每个用户只能返回一行。