仅显示与条件匹配的结果

时间:2013-07-11 20:36:57

标签: php mysql

我正在尝试做一些MySQL魔术,而且我遇到了一堵墙。

基本上,这将是将相关帖子拉入用户主要“新闻源”页面的代码。但是,它不是从朋友那里拉扯帖子的;它正在从系统中同一组内的任何人那里提取帖子,但它(显然)不应该显示阻止他们的人的帖子。我理解JOIN过程,但是我无法找到后一部分的正确语法。

这是当前的查询:

SELECT stories.id
FROM stories
JOIN users ON stories.posterID=users.id
JOIN relationships ON relationships.user1=stories.posterID
WHERE users.schoolID='$school'
AND (relationships.rel <> '3' WHERE relationships.user2=stories.posterID)

“rel”字段只是用户与用户“关系”的标志;在这种情况下,3表示它们已被阻止,但由于显而易见的原因,这些用户之间可能根本没有关系输入。有没有办法去做呢?

2 个答案:

答案 0 :(得分:1)

我想我可以看到你想要做什么,试一试:

SELECT 
  stories.id
FROM 
  stories
INNER JOIN 
  users ON users.id = stories.posterID
INNER JOIN 
  relationships ON relationships.user1 = users.id
WHERE 
  users.schoolID = '$school'
AND
  NOT EXISTS (
    SELECT 
      1 
    FROM 
      relationships AS r 
    WHERE 
      r.user1 = users.id 
    AND 
      r.user2 = stories.posterID 
    AND 
      r.rel = 3 
  )

答案 1 :(得分:0)

是的,可以返回指定的结果集。通常,返回此类结果的最有效方法是使用反连接模式。

似乎缺少的是一个谓词,用于标识您正在提取新闻源的用户。

如果没有这个,那么阻止另一个用户(B)的任何用户(A)也将阻止来自用户B的所有其他用户的故事......没有人能够看到来自用户B的故事。似乎关系表中的一个块行意味着单个用户“阻止”来自另一个用户的故事。

SELECT s.id
  FROM stories s
  JOIN users u
    ON u.id = s.posterID
  LEFT
  JOIN (
         SELECT r.user2
           FROM relationships r
          WHERE r.rel = '3'
            AND r.user1 = 'me'
       ) b
    ON b.user2 = u.id
 WHERE b.user2 IS NULL
   AND u.schoolID='$school'

让我们稍微打破一下,首先,消除内联视图别名为b。

此查询应返回具有给定schoolID的所有用户发布的所有故事。

SELECT s.id
  FROM stories s
  JOIN users u
    ON u.id = s.posterID
 WHERE u.schoolID='$school'

现在,我们想要阻止来自任何用户的故事,这个用户(让我们叫他'我')选择阻止。

我将假设“阻塞”是如何工作的。我将假设如果user1='me'已阻止“user2”,则意味着“user2”中的故事不应呈现给“我”。这将通过一行

在关系表中表示
(user1='me','user2',3)

如果这是对的,则表示此查询:

SELECT r.user2
  FROM relationships r
 WHERE r.rel = '3'
   AND r.user1 = 'me'

将返回已被用户“我”阻止的所有用户的列表。

“技巧”现在是使用第一个查询的结果对此结果进行左连接,然后丢弃我们找到匹配项的任何行。这被称为“反连接”模式。请注意,IS NULL谓词是消除匹配行的原因。


跟进:

问:如果我想避免向拦截器和被阻止的人显示“故事”,我可以进行简单的修改......

答:如果关系表中的“阻止”行如下所示:

(user1='me',user2,3)

我们之前认为用户'我'选择不看用户2的任何故事。

如果我们也希望将同一行解释为意味着用户'我'也选择不允许用户2看到'我'的故事,这是我们需要做的另一项检查,但这并不困难。

如果我们回到查询中查找被“我”阻止的用户,(其中“我”不希望看到来自user2的故事)

SELECT r.user2
  FROM relationships r
 WHERE r.rel = '3'
  AND r.user1 = 'me'

我们可以在该查询中交换user1和user2的位置,如下所示:

SELECT r.user1
  FROM relationships r
 WHERE r.rel = '3'
  AND r.user2 = 'me'

这将获得已选择阻止“我”的用户列表。

要从这些用户中排除故事,我们将该查询(作为内联视图)添加到原始查询,并执行相同的反连接模式:查找“匹配行”,然后排除找到匹配项的所有行。

在下面的查询中,新的内联视图被赋予了别名d(没有特殊原因,除了'd'看起来像是'b'的镜像)

SELECT s.id
  FROM stories s
  JOIN users u
    ON u.id = s.posterID
  LEFT
  JOIN (
         SELECT r.user2
           FROM relationships r
          WHERE r.rel = '3'
            AND r.user1 = 'me'
       ) b
    ON b.user2 = u.id
  LEFT
  JOIN (
         SELECT r.user1
           FROM relationships r
          WHERE r.rel = '3'
            AND r.user2 = 'me'
       ) d
    ON d.user1 = u.id
 WHERE b.user2 IS NULL
   AND d.user1 IS NULL
   AND u.schoolID='$school'

注意:我没有测试过,但是如果我对需求的理解是合理的话,似乎会返回指定的结果集。

给它一个旋转,让我知道有多大的烟球。