0

我正在尝试做一些 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 表示他们已被阻止,尽管出于显而易见的原因,这些用户之间可能根本不存在关系条目。有什么办法可以做到这一点?

4

2 回答 2

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 
  )
于 2013-07-11T20:51:11.700 回答
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谓词是消除匹配行的原因。


跟进:

问:如果我想避免向阻止者和被阻止者显示“故事”,我可以做一个简单的修改...

A:如果关系表中的“block”行是这样的:

(user1='me',user2,3)

我们之前认为这意味着用户“我”选择不看到来自 user2 的任何故事。

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

如果我们返回查询查找被“我”阻止的用户,(“我”不想看到来自用户 2 的故事)

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'

注意:我还没有测试过,但如果我对要求的理解是正确的,它似乎会返回指定的结果集。

试一试,让我知道一个烟球有多大。

于 2013-07-11T20:55:16.667 回答