【问题标题】:How to exclude rows from a SQL fetch that have a related keyword through a many to many relationship如何通过多对多关系从 SQL 提取中排除具有相关关键字的行
【发布时间】:2019-06-01 18:54:45
【问题描述】:

我有一个 MySQL 数据库,其中包含一个 media 表和一个 keywords 表,以及 mediakeywords 之间通过 media_keywords 连接表的多对多关系。

我想从媒体表中获取满足以下条件集的所有记录:

'description' is like 'dog' OR 
'media.keywords' includes the id for the 'dog' keyword [100]

并从搜索结果中排除以下任何记录:

'description' is like 'cat' OR
'media.keywords' includes the id for the 'cat' keyword [400]

并且还排除以下任何行:

'media.keywords' includes the id for the 'monochrome' keyword [500]

我也想只返回不同的行,所以我使用 GROUP By 'media.id'

我现在的SQL语句如下:

    SELECT DISTINCT 
    `media`.`id`,`media`.`description`, 
    `keywords`.`id` AS `keywords.id`, 
    `keywords->media_keywords`.`id` AS `keywords.media_keywords.id`, 
    `keywords->media_keywords`.`media_id` AS `keywords.media_keywords.media_id`, 
    `keywords->media_keywords`.`keyword_id` AS `keywords.media_keywords.keyword_id` 

    FROM database.media 

    LEFT OUTER JOIN 
    ( 
        `media_keywords` AS `keywords->media_keywords` 

        INNER JOIN `keywords` AS `keywords` 
        ON `keywords`.`id` = `keywords->media_keywords`.`keyword_id`
    ) 

    ON `media`.`id` = `keywords->media_keywords`.`media_id` 

    WHERE 
    ( 
            (`media`.`description` LIKE '%dog%' ) 

            OR `keywords`.`id` IN (100) 
    )

    AND NOT 
    ( 
            (`media`.`description` LIKE '%cat%' ) 

            OR `keywords`.`id` IN (400,500)
    )

    GROUP BY `media`.`id` ;

这会正确获取描述中包含“dog”或关键字的记录,但会完全忽略排除项。

谁能看到我在这里做错了什么?

【问题讨论】:

  • 您的别名比您的表名长。我感觉不舒服。
  • 另外,您不太可能使用区分大小写的排序规则 - 只是说'
  • 你想排除像'scathing'这样的词吗?
  • @Strawberry - 我检查了,你是对的,排序规则不区分大小写,所以 lower() 不是必需的 - 我已经删除了它。我是一名前端开发人员,学习后端,在网上发现信噪比充其量是低的,所以我确信有很多事情我没有按照最佳标准做。我并没有被严厉的 cmets 压垮,但我更喜欢更有帮助的 cmets。如果您有关于如何更有效地解决此问题的建议,这就是我希望听到的,我们将不胜感激。干杯!
  • 只是一个问题,看我之前的评论

标签: mysql sql


【解决方案1】:

我会使用where 子句:

select m.*
from media m
where (m.description like '%dog%' or
       exists (select 1
               from keywords k
               where k.media_id = m.id and
                     k.keyword_id = 100
              )
      ) and
      (m.description not like '%cat%' or
       exists (select 1
               from keywords k
               where k.media_id = m.id and
                     k.keyword_id in (400, 500)
              )
       );

这几乎是您的条件的直接翻译。

【讨论】:

    【解决方案2】:

    我不经常使用 mySQL,但我会建议一种不同的方法

    • 将“DOG”条件移到 LEFT JOIN 中(所以只获取关键字 匹配 "DOG") 并使其成为 JOIN。现在您将拥有所有列表 匹配。
    • 在 WHERE 子句中添加子查询
    • 其中 id 不在(SELECT id FROM ... WHERE LIKE '%cat%')

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-08
      相关资源
      最近更新 更多