【问题标题】:What Would be the Correct SELECT Statement for This?什么是正确的 SELECT 语句?
【发布时间】:2016-03-25 11:13:38
【问题描述】:
SELECT *
  FROM notifications
  INNER JOIN COMMENT
    ON COMMENT.id = notifications.source_id
      WHERE idblog IN (SELECT blogs_id
        FROM blogs
        WHERE STATUS = "active")
  INNER JOIN reportmsg
    ON reportmsg.msgid = notifications.source_id
      WHERE uid =: uid
  ORDER BY notificationid DESC
  LIMIT 20;

我在这里 INNER JOINing notificationscommentreportmsg;然后用WHERE过滤内容。

但我的问题是,对于第一个INNER JOIN [即与comment],在加入notificationscomment 之前,我想将notifications.idblogblogs.blogs_id 匹配 em> SELECT 只有blogs.status = "active" 所在的那些行。

为了更好地理解上面的代码:

这里,对于INNER JOIN,对于comment,我只想SELECT notifications 中那些idblog 匹配blogs.blogs_id 的行并且status = "active"。 p>

第二个INNER JOINreportmsg 不需要更改。也就是说,它只过滤uid

【问题讨论】:

  • 用于与关系数据库交互的语言称为 SQL,而不是 PHP。我已相应地编辑了您的问题。
  • 由于COMMENT 是关键字,我会小心并在其周围加上反引号。
  • @bɪˈɡɪnə 检查我的答案是否满足......并告诉我在我的答案中错过了什么......

标签: mysql sql inner-join


【解决方案1】:

从下图中可以看出,您只需像这样使用LEFT JOIN 将其他表合并到通知表即可:

SELECT n.notificationid, n.uid, n.idblog, n.source_id, 
       b.blogs_id, b.status,
       c.id, 
       r.msgid
       -- ... and the other columns you want
FROM notifications n
LEFT JOIN blogs b ON b.blogs_id = n.idblog AND b.STATUS = "active" AND n.uid =: uid
LEFT JOIN comment c ON c.id = n.source_id    
LEFT JOIN reportmsg r ON r.msgid = n.source_id
ORDER BY n.notificationid DESC
LIMIT 20;


希望这会有所帮助...

【讨论】:

  • 如果您有WHERE b.STATUS = "active",则LEFT JOIN blogs b 没有意义...这有效地将其还原为INNER JOIN
  • @Arth 你说得对,我更新了我的答案并将“WHERE”子句中的条件移动到“ON”。谢谢。
  • 干杯,但现在您会收到所有通知、cmets 和 reportmsgs,并且只过滤匹配的博客。很确定这不是 OP 想要的。
  • 图片最有可能来自this answer
  • @SverriM.Olsen 是的,但问题不是“图像来自哪里?”。如果您有任何想法,请发布您的答案。谢谢。
【解决方案2】:

没有必要/理由在第二个连接之前进行过滤,因为您只使用内部连接,然后连接的顺序和 WHERE 条件无关紧要:

SELECT n.*, c.*, r.*
FROM notifications AS n
JOIN COMMENT  as c 
  ON n.source_id = c.id
LEFT JOIN blogs as b
  ON n.idblogs = b.blogs_id
 AND B.STATUS = 'active'
JOIN reportmsg AS R
  ON n.source_id = r.msgid 
WHERE uid =: uid
ORDER BY notificationid DESC
LIMIT 20

您可以切换连接的顺序,您可以将B.STATUS = 'active' 移动到连接条件中,但所有查询都将返回相同的结果。 (编辑后是LEFT JOIN,当然现在结果不同了)

当然你不应该使用*,最好只列出你真正需要的列。

【讨论】:

  • 单独join 不选择任何行,使用LEFT JOIN 进行评论和reportmg 和INNER JOIN 用于博客工作但条件where STATUS='actiive' 适用于comment 表和reportmsg有什么办法可以仅在评论表上应用该条件?
  • @bɪˈɡɪnə:如果您添加一些示例数据会更容易 :-) 您可能需要将 STATUS='active' 移动到连接中,我将编辑我的答案..
【解决方案3】:

如果查询优化器完成了它的工作,那么在INNER JOIN 的情况下将过滤语句放在哪里都没有关系,但在LEFT JOIN 中它会产生效果。将过滤语句放在LEFT JOIN 条件中会导致表先过滤后加入,而将过滤语句放在WHERE 子句中将过滤连接结果。因此,如果您想使用LEFT JOIN,您的查询必须如下所示:

  SELECT nt.*
  FROM notifications nt
  LEFT JOIN Blogs bg on nt.blogs_id = bg.blogs_id and bg.STATUS = "active"
  LEFT JOIN COMMENT cm ON cm.id = nt.source_id         
  LEFT JOIN reportmsg rm ON rm.msgid = nt.source_id
  WHERE uid =: uid
  ORDER BY nt.notificationid DESC
  LIMIT 20;

【讨论】:

    【解决方案4】:

    目前还不清楚您在这里追求什么。虽然您的表格图很有用,但您应该真正提供一些示例数据和预期结果,即使每个表格只是几个虚拟行。

    查询逐行进行,两个 INNER JOIN 都应用于同一通知行,不匹配的行将被丢弃。

    任何过滤器都适用于 JOIN,并且任何返回的行必须在 BOTH comment 和 reportmsg 中都匹配。

    也许您想要两个可以应用不同过滤器的 LEFT JOIN,并根据表名猜测它可能看起来像这样:

       SELECT *
         FROM notifications n
    LEFT JOIN blogs b
           ON n.blogId = b.blogs_id
    LEFT JOIN comment c
           ON c.id = n.source_id
          AND b.status = "Active"
    LEFT JOIN reportmsg rm
           ON rm.msgid = n.source_id
        WHERE n.uid =: uid
          AND (c.id IS NOT NULL OR rm.msgid IS NOT NULL)
     ORDER BY n.notificationid DESC
        LIMIT 20 
    

    您还应该遵守您的命名约定:

    • 通知、评论 -> 选择复数或单数表名
    • notifications.notificationid, comment.id -> 选择将表名添加到 id
    • notificationid、source_id -> 选择下划线或不分隔
    • idblog、notificationid -> 选择前置或附加 id

    目前,您几乎必须在每次要使用一个 id 字段时查找每个字段。

    【讨论】:

      【解决方案5】:

      您应该将查询更改为:

      SELECT * 
      FROM notifications 
      INNER JOIN comment ON comment.id = notifications.source_id 
      INNER JOIN reportmsg ON reportmsg.msgid=notifications.source_id 
      LEFT JOIN blogs ON notifications.idblog = blogs.blogs_id
      WHERE blogs.status = 'active'
      ORDER BY notificationid DESC 
      LIMIT 20;
      

      【讨论】:

      • thanx 但我希望 status='active' 条件仅适用于第一个内部连接
      • 如果您的查询的其余部分正常工作,但只有这部分没有工作,那么为什么不在 INNER JOIN 语句之后放置 status = 'active' 。像这样:INNER JOIN comment ON comment.id = notifications.source_id AND status = 'active'
      • "INNER JOIN comment ON (comment.id = notifications.source_id AND comment.status='active')"..考虑到您的 cmets 表有状态列。
      • 如果你有WHERE blogs.status = "active"LEFT JOIN blogs 没有意义...这有效地将其还原为INNER JOIN
      猜你喜欢
      • 1970-01-01
      • 2020-08-05
      • 2018-05-29
      • 1970-01-01
      • 2013-01-24
      • 2019-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多