MySQL 返回其中列包含集合中的任何但仅包含关键字的所有行

2024-01-09

有没有一种方法可以选择其中一列仅包含但任意数量的预定义值的行?

我一直在使用这个,但它返回我的列至少包含一个值的任何行(我知道这正是它应该做的)。

但我正在寻找一种方法来仅选择关键字列中仅包含我的关键字的行。

SELECT * 
FROM 
    `products`.`product` 
WHERE 
    keywords LIKE '%chocolate%' 
AND keyword LIKE '%vanilla%';

关键词示例:chocolate, sugar, milk, oats

使用上面的关键字,我希望返回前两个结果,而不是最后两个:

Product1: chocolate, sugar 

Product2: chocolate 

Product3: chocolate, sugar, milk, oats, bran 

Product4: chocolate, sugar, salt

我的列包含适用于该产品行的所有关键字的逗号分隔列表。


由于您将列表存储为包含逗号分隔列表的字符串,而不是作为集合,因此 MySQL 将无法提供太多帮助。当它被插入数据库时​​,MySQL 将其视为单个字符串。当从数据库中检索它时,MySQL 将其视为单个字符串。当我们在查询中引用它时,MySQL 将其视为单个字符串。


如果“列表”存储为标准关系集,产品的每个关键字存储为表中的单独行,那么返回您指定的结果集几乎是微不足道的。

例如,如果我们有这张表:

CREATE TABLE product_keyword 
product_id      BIGINT UNSIGNED COMMENT 'FK ref products.id'
keyword         VARCHAR(20)

将与特定产品相关联的每个关键字作为单独的行:

product_id keyword
---------- ---------
         1 chocolate
         1 sugar
         2 chocolate
         3 bran
         3 chocolate
         3 milk
         3 oats
         3 sugar
         4 chocolate
         4 salt
         4 sugar

然后查找所有行product具有除以下之外的关键字'chocolate' or 'vanilla'

SELECT p.id
  FROM product p
  JOIN product_keyword k
 WHERE k.product_id = p.id
    ON k.keyword NOT IN ('chocolate','vanilla')
 GROUP BY p.id

--or--

SELECT p.id
  FROM product p
  LEFT
  JOIN ( SELECT j.id
           FROM product_keyword j
          WHERE j.keyword NOT IN ('chocolate','vanilla')
         GROUP BY j.id
       ) k
    ON k.id = p.id 
 WHERE k.id IS NULL

要获取至少具有关键字“巧克力”和“香草”之一但没有关联其他关键字的产品,与上面的查询相同,但具有附加联接:

SELECT p.id
  FROM product p
  JOIN ( SELECT g.id
           FROM product_keyword g
          WHERE g.keyword IN ('chocolate','vanilla')
         GROUP BY g.id
       ) h
    ON h.id = p.id 
  LEFT
  JOIN ( SELECT j.id
           FROM product_keyword j
          WHERE j.keyword NOT IN ('chocolate','vanilla')
         GROUP BY j.id
       ) k
    ON k.id = p.id 
 WHERE k.id IS NULL

我们可以解压这些查询,它们并不困难。询问h返回至少具有一个关键字的product_id列表,查询k返回包含指定关键字之外的某些关键字的product_id 列表。那里的“技巧”(如果你想这样称呼它)是反连接模式...执行外连接来匹配行,并包含没有匹配的行,以及 WHERE 子句中的谓词消除具有匹配项的行,留下产品中不具有匹配项的行集。


但是,如果将集合存储为单个字符列中的“逗号分隔列表”,我们就失去了关系代数的所有优点;没有任何简单的方法可以将关键字列表处理为“集合”。

由于整个列表存储为单个字符串,我们需要使用一些可怕的 SQL 来获取指定的结果。

执行您指定的检查类型的一种方法是创建一组所有可能的“匹配项”,然后检查它们。这对于几个关键字是可行的。例如,要获取仅包含关键字的产品列表'vanilla' and/or 'chocolate',(也就是说,至少具有这些关键字之一并且没有任何其他关键字):

SELECT p.id
  FROM product 
 WHERE keyword_list = 'chocolate'
    OR keyword_list = 'vanilla'
    OR keyword_list = 'chocolate,vanilla'
    OR keyword_list = 'vanilla,chocolate'

但是,将其扩展到三个、四个或五个关键字很快就会变得笨拙(除非保证关键字以特定顺序出现)。并且检查四个关键字中的三个非常困难。

另一种(丑陋的)方法是改变keyword_list成一个集合,以便我们可以使用像我的答案中的第一个查询一样的查询。但是执行转换的 SQL 受到可以从 keywords_list 中提取的任意最大关键字数量的限制。

使用一些简单的 SQL 字符串函数从逗号分隔列表中提取第 n 个元素相当容易,例如,从逗号分隔列表中提取前五个元素:

SET @l := 'chocolate,sugar,bran,oats'
SELECT NULLIF(SUBSTRING_INDEX(CONCAT(@l,','),',',1),'')                         AS kw1
     , NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(@l,','),',',2),',',-1),'') AS kw2
     , NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(@l,','),',',3),',',-1),'') AS kw3
     , NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(@l,','),',',4),',',-1),'') AS kw4
     , NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(@l,','),',',5),',',-1),'') AS kw5

但它们仍然在同一排。如果我们想对这些进行检查,我们需要进行一些比较,我们需要检查其中的每一个,看看它是否在指定的列表中。

如果我们可以将一行上的这些关键字转换为一组行,每行上有一个关键字,那么我们可以使用像我的答案中的第一个查询那样的查询。举个例子:

SELECT t.product_id
     , NULLIF(CASE n.i
       WHEN 1 THEN SUBSTRING_INDEX(CONCAT(t.l,','),',',1)
       WHEN 2 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(t.l,','),',',2),',',-1)
       WHEN 3 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(t.l,','),',',3),',',-1)
       WHEN 4 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(t.l,','),',',4),',',-1)
       WHEN 5 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(t.l,','),',',5),',',-1)
       END,'') AS kw
  FROM ( SELECT 4 AS product_id,'fee,fi,fo,fum' AS l  
          UNION ALL 
         SELECT 5, 'coffee,sugar,milk'
        ) t
 CROSS
  JOIN ( SELECT 1 AS i
         UNION ALL SELECT 2
         UNION ALL SELECT 3
         UNION ALL SELECT 4
         UNION ALL SELECT 5
       ) n
HAVING kw IS NOT NULL
ORDER BY t.product_id, n.i

这为我们提供了单独的行,但它仅限于前 5 个关键字中的每一个的行。很容易看出如何扩展(让 n 返回 6,7,8,...)并扩展 CASE 中的 WHEN 条件来处理 6,7,8...

但会有一些任意的限制。 (我使用了内联视图,别名为t,返回两个“示例”行,作为演示。该内联视图可以替换为对包含product_id 和keyword_list 列的表的引用。)

因此,该查询为我们提供了一个行集,就像从product_keyword我在上面给出的表作为例子。

在示例查询中,引用了product_keyword表可以用此查询替换。但这是一大堆难看的 SQL,而且效率极其低下,每次运行查询时都会创建和填充临时 MyISAM 表。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MySQL 返回其中列包含集合中的任何但仅包含关键字的所有行 的相关文章

随机推荐

  • 播放服务广告与 appcompat 冲突

    当我添加implementation com google android gms play services ads 18 2 0 到我的 build gradle Android Studio 亮点implementation com
  • 如何强制mongo以小写形式存储成员?

    我有一个 BsonDocuments 集合 例如 MongoCollection
  • 为什么绑定不适用于动画?

    我对动画绑定属性有一个简单的问题 这是一个简单的例子来说明它 视图模型 public class ViewModel private double myProperty public double MyProperty get return
  • 在 JavaScript 中检测 Lion (OS X 10.7)?

    有没有办法用 Javascript 检测操作系统是否是 OS X Lion Cheers Lion 中 Safari 还有 Firefox 的用户代理类似于 Mozilla 5 0 Macintosh Intel Mac OS X 10 7
  • 如何从 Amazon API Gateway 将查询字符串或路由参数传递到 AWS Lambda

    例如如果我们想使用 GET user name bob or GET user bob 如何将这两个示例作为参数传递给 Lambda 函数 我在文档中看到了有关设置 映射自 的内容 但我在 API Gateway 控制台中找不到该设置 me
  • Kotlin 中具有反向查找功能的有效枚举?

    我正在尝试找到在 Kotlin 中对枚举进行 反向查找 的最佳方法 我从 Effective Java 中得到的收获之一是在枚举中引入静态映射来处理反向查找 使用一个简单的枚举将其移植到 Kotlin 会得到如下所示的代码 enum cla
  • 关于 (POSIX) 信号主题的最佳参考文献是什么?

    信号似乎是概念上应该简单且易于解释的领域之一 但我从未遇到过既全面 清晰又最新的来源 在某种程度上 这似乎是由于历史遗留问题 规则的大量例外 不同的编程标准 混乱的线程 实时添加等 关于 unix linux posix 信号 您写得最好
  • 如何在 Asp.net MVC2 中通过 Ajax 调用处理 UnauthorizedRequest

    Brief 我的框架中有一个子类 AuthorizeAttribute 我在其中进行自定义授权 我正在从普通的 asp net mvc 视图渲染切换到通过 jQuery 的 Ajax 渲染 因此 应用程序中的每个链接都会执行 ajax 调用
  • Firefox 中的内联 SVG

    我对这个有点难住了 我使用 Protovis 一个 JS 库 渲染 SVG 可视化 它在 Chrome 和 Firefox 中运行得非常好 我将渲染的 SVG 保存在我的服务器上 并尝试使用 PHP 函数在 图库 视图中重新渲染它 但这在
  • Python Gtk 3.0:如何在 Notebook 中获取焦点

    我正在尝试将焦点设置为Entry输入字段 如果我把它放在一个Box 我可以通过设置焦点grab focus方法 但如果Entry是在一个里面Notebook 它没有聚焦 示例代码 import gi gi require version G
  • querySelectorAll 无法识别 var

    我正在使用 casperjs 进行一些网络抓取 但遇到了一个奇怪的问题 我希望能够从字符串构造 CSS 路径并使用 querySelectorAll 获取数组 如下所示 var tier ou var index div list gt d
  • sed:替换行的一部分

    如何用 sed 替换一行的一部分 线路 DBSERVERNAME xxx 应替换为 DBSERVERNAME yyy 值 xxx 可能会有所不同 并且 dbservername 和该值之间有两个选项卡 该名称 值对是配置文件中的众多名称 值
  • github PR 显示所有过去的提交

    我们最近改变了工作流程 我们在 github 上的 新 存储库有 2 个分支 master and develop master不受直接推送保护 仅合并 PR develop是所有乐趣发生的地方 功能分支被合并回develop git me
  • 在 Angular 2 中使用第三方库 (parse.com)

    我正在学习 Angular 2 并且已经遵循 Egghead 的教程 但我对有关 Angular 的一切都很陌生 现在我想做一些更高级的事情并开始将 Parse com 与 A ngular 2 结合使用 通常我会通过以下方式将 parse
  • OPC 节点路径中的“ns=2;s=”有何意义?

    我注意到所有 OPC 标签 ID 的前缀都是ns 2 s 可能的 NodeId 值的一些示例是 ns 2 s AcquisitionTimeRemaining ns 2 s Status ns 2 s Time 我想知道这个前缀的意义是什么
  • 在 Flutter 中创建自定义小部件

    import package flutter material dart import package font awesome flutter font awesome flutter dart int weight 60 class R
  • 获取城市名称不以元音开头或不以元音结尾

    从 STATION 查询不以元音开头或不以元音结尾的 CITY 名称列表 您的结果不能包含重复项 输入格式 STATION表描述如下 我写了下面的查询 但它对我不起作用 有什么建议吗 select distinct city from st
  • GitHub - 查找与提交关联的拉取请求

    我正在尝试查找过去的拉取请求 以查看对特定问题做出了哪些评论 操作 我知道该文件和更改 因此我可以通过查看指责视图来访问引入该文件的提交 但是 我找不到一种方法来查看第一次将该提交推送到分支的拉取请求 有没有办法做到这一点 或者我是否必须沿
  • ./*/ 是可移植的吗?

    我经常使用 在 for 循环中 for d in do do something with dirs done 匹配当前工作目录中的所有非隐藏目录 但我不确定这是否是一种可移植的方法 我的系统上安装了 bash dash 和 ksh 并且它
  • MySQL 返回其中列包含集合中的任何但仅包含关键字的所有行

    有没有一种方法可以选择其中一列仅包含但任意数量的预定义值的行 我一直在使用这个 但它返回我的列至少包含一个值的任何行 我知道这正是它应该做的 但我正在寻找一种方法来仅选择关键字列中仅包含我的关键字的行 SELECT FROM product