什么是正确的SELECT语句?

时间:2016-03-25 11:13:39

标签: mysql sql inner-join

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 JOIN notifications commentreportmsg;然后使用WHERE过滤内容。

但我的问题是,对于第一个INNER JOIN [即,使用comment],在notifications加入comment之前,我希望匹配notifications.idblog blogs.blogs_id SELECT仅包含blogs.status = "active"的行。

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

ER diagram

此处,对于INNER JOIN,对于comment,我想SELECTnotifications idblog匹配blogs.blogs_id status = "active"行并且INNER JOIN

reportmsguid的第二个PHFetchOptions *options = [[PHFetchOptions alloc] init]; options.includeAssetSourceTypes = PHAssetSourceTypeUserLibrary; PHFetchResult *allPhotosResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:options]; PHImageRequestOptions *requestOptionForPhotos = [[PHImageRequestOptions alloc] init]; requestOptionForPhotos.networkAccessAllowed = YES; for(PHAsset *asset in allPhotosResult) { [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:CGSizeMake(100, 100) contentMode:PHImageContentModeAspectFill options:requestOptionForPhotos resultHandler:^(UIImage *result, NSDictionary *info) { NSData *data = UIImagePNGRepresentation(result); NSString *base = [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]; // for some of photos there is nil }]; } 无需更改。即,它仅通过src进行过滤。

5 个答案:

答案 0 :(得分:5)

从下图中可以看出,您只需要使用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; 将其他表合并到通知表中:

infix operator ? : { precedence 120 }


SQL JOINS

希望这会有所帮助......

答案 1 :(得分: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,当然现在结果不同了)

当然,您不应该使用*,最好只列出您实际需要的列。

答案 2 :(得分:1)

如果查询优化器能够正常工作,那么在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;

答案 3 :(得分:0)

目前还不清楚你的目标是什么......虽然你的表格图很有用,你应该提供一些样本数据和预期结果,即使它只是每个表的几个虚拟行。

查询逐行工作,两个INNER JOIN都应用于同一通知行,并且丢弃不匹配的行。

任何过滤器都适用于两个JOIN,任何返回的行必须在BOTH注释和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字段。

答案 4 :(得分:-1)

您应该将查询更改为:

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;