【问题标题】:MySQL Query show results based on multiple filters/tagsMySQL Query 显示基于多个过滤器/标签的结果
【发布时间】:2013-10-09 15:37:15
【问题描述】:

以前曾以不同的方式提出过这个问题,但我似乎无法得到适合我确切需要的东西。

这里的目标是创建一个搜索查询,根据所选标签返回照片。许多标签可以同时应用于过滤器,这需要使查询只返回选择了所有标签的照片。想想在执行基本关键字搜索后您正在缩小结果范围的任何主要网上商店。

表 1:照片 ID|标题|描述|URL|已创建

表 2:PhotosTagsXref ID|PhotoId|TagId

表 3:照片标签 ID|标题|类别

我有什么:

SELECT p.* FROM `PhotosTagsXref` AS pt
LEFT JOIN `Photos` AS p ON p.`ID` = pt.`PhotoId`
LEFT JOIN `PhotosTags` AS t ON pt.`TagId` = t.`ID`
WHERE p.`Description` LIKE "%test%" AND 
????
GROUP BY p.`ID`
ORDER BY p.`Created` DESC LIMIT 20

????是我尝试了很多东西但被难住的地方。问题是我可以轻松找到包含带有一个或另一个标签的照片的结果集,但如果应用 2、3 或 4 个标签,我们只需要返回在数据库中包含所有这些标签条目的照片。我认为这将涉及合并结果集,但不是 100% 确定。

示例: 照片 1 标签:蓝色、白色、红色 照片 2 标签:蓝色

搜索带有“蓝色”标签的照片会返回两张照片,搜索带有“蓝色”和“白色”标签的照片只会返回照片 1。

【问题讨论】:

  • 也许 CONTAINS 子句会对你有所帮助。
  • 我会使用内部连接到子选择语句。您如何构建此查询以及如何获取输入?如果标签数量有上限,那么您可以在此处执行仅 SQL 语句。如果您对标签没有限制,那么您需要在构建 sql 语句时更加动态。
  • 按照下面的解决方案进行内部连接可以解决问题,谢谢。该查询是从 GET 请求构建的,包含一个过滤器数组变量,理论上无限数量的标签。有一个逻辑限制,但我想它可能在 10 - 20 范围内。
  • 我把它放在我的答案中......但只是对 MySQL 的警告......它根本不能很好地处理子选择(查询引擎对它的评估很差)。 where exists 的性能比 where in 好,但是如果你期望这个数据库增长任何,我会非常警惕在 MySQL 中实现子查询(我对这个问题的解决方案是使用 Postgres 而不是 MySQL :))

标签: mysql sql


【解决方案1】:

假设请求的标签集是 (red,blue) 你可以这样做:

SELECT * FROM `Photos` 
WHERE `Description` LIKE "%test%" 
AND `ID` IN (
  SELECT pt.`PhotoId` FROM `PhotosTagsXref` AS pt
  JOIN `PhotosTags` AS t ON pt.`TagId` = t.`ID`
  WHERE t.Title in ('red','blue') /* your set here */
  GROUP BY pt.`PhotoId` HAVING COUNT(DISTINCT t.`TagId`)=2 /* # of tags */
  )
ORDER BY `Created` DESC LIMIT 20

显然,标签集需要动态创建,以及它的计数。

注意:我计算的是DISTINCTTagIDs,因为我不知道你的表的约束。如果PhotosTagsXRef 有一个PK/UNIQUE (PhotoId,TagId) 并且PhotosTags 有一个PK/UNIQUE (TagId),那么COUNT(*) 就足够了。

【讨论】:

  • 谢谢。为我工作!
【解决方案2】:

诚然有点难看。但假设 PhotosTags.Category 有“蓝色”、“白色”等,请尝试沿着这条线。

SELECT p.* 
From `Photos` AS p
WHERE p.`Description` LIKE "%test%" AND 
  AND Exists
      ( Select 1 FROM `PhotosTagsXref` AS pt
        Inner JOIN `PhotosTags` AS t ON pt.`TagId` = t.`ID`
        Where pt.`PhotoId` = p.`ID`
          And t.Category = 'FirstCatToSearch'
      )   
  AND Exists
      ( Select 1 FROM `PhotosTagsXref` AS pt
        Inner JOIN `PhotosTags` AS t ON pt.`TagId` = t.`ID`
        Where pt.`PhotoId` = p.`ID`
          And t.Category = 'SecondCatToSearch'
      )   
  AND Exists
      ( ...
      )   
      ...

【讨论】:

  • 这成功了,也许不像你说的那么好,但它确实有效。速度似乎也没有异常。
【解决方案3】:
SELECT p.* FROM `PhotosTagsXref` AS pt
LEFT JOIN `Photos` AS p ON p.`ID` = pt.`PhotoId`
LEFT JOIN `PhotosTags` AS t ON pt.`TagId` = t.`ID`
inner join (select PhotoId from PhotosTagsXref 
             LEFT JOIN `PhotosTags` AS t 
             ON pt.`TagId` = t.`ID`
             where (t.title = 'cond 1' or t.title = 'cond 2' ...)
             --where t.title in (list condition)    **this works as well**
             having count(1) = (count of conditions) ) filter
  on filter.photoID = pt.PhotoID
WHERE p.`Description` LIKE "%test%"
GROUP BY p.`ID`
ORDER BY p.`Created` DESC LIMIT 20

这应该可行,我对过滤器和连接使用的列做了一些假设,您可能需要重新工具...内部连接用作过滤器,并且应该只提取匹配数相等的记录提交的比赛总数。现在您只需要一种语言来插入这些条件和条件计数值。

【讨论】:

  • 这可能也有效,但我无法正确调整它,也许是我的错,但其他解决方案对我有用。
  • 只是一个警告...MYSQL 在子选择方面存在一些已知的性能问题。此处的 where exists 使用确实对其进行了优化,但如果您开始遇到 MySQL 查询的性能问题,则一系列 if exists 语句可能是罪魁祸首。情侣链接...mysqldbahelp.com/2010/03/subselect-vs-join-performanace.html#!/…stackoverflow.com/questions/16403860/…
  • 性能可能是一个问题,所以我一定会看看,连接通常也是我的偏好,我只是出于某种原因无法解决这个问题。
  • 是的,我在过去使用 MySQL 时对此有所了解,认为您应该注意这一点。我对我的答案进行了更改,可能会更简单。 where t.title in (list conditions) 与我使用的 or 语句一样有效。
  • 最后一个问题,关于这部分:(条件计数),你能举个例子说明实际应该是什么吗?我想我已经解决了剩下的问题,然后我也可以将其标记为一个好的解决方案。
猜你喜欢
  • 1970-01-01
  • 2011-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-30
  • 1970-01-01
  • 2011-09-06
  • 2023-02-22
相关资源
最近更新 更多