基于SQL标记的搜索,具有逻辑AND行为而不是OR

时间:2015-04-10 13:46:43

标签: mysql regex

我有一个使用下表设置的mysql数据库

CREATE TABLE IF NOT EXISTS Company(
name VARCHAR(25) NOT NULL,
description VARCHAR(512) NOT NULL,
PRIMARY KEY(name)
);

CREATE TABLE IF NOT EXISTS CompanyTag(
companyName VARCHAR(25) NOT NULL,
tag VARCHAR(25) NOT NULL,
PRIMARY KEY(companyName, tag)
);

导致看起来像这样的CompanyTag表

Company            Tag
someCompany1      first
someCompany1      second
someCompany1      third
someCompany2      first
someCompany2      second
someCompany3      first

当搜索是“第一个第二个第三”时,只应返回someCompany1。当搜索是“第一秒”时,只应返回someCompany1和2。 当搜索“第一次”时,应该返回someCompany1,2和3。

目前,我可以通过执行以下查询来搜索包含一个或多个单词的公司

SELECT name, description, location, website, categoryName FROM Company 
INNER JOIN CompanyTag ON CompanyTag.companyName = Company.name
WHERE tag REGEXP ?;

where ? is "^(.*first.*|.*second.*|.*third.*)$"

然而,正如您所期望的那样,这会产生ORing标记

的效果

我可以对数据库或查询的结构做些什么来使我能够和标签相反,即。获得公司被标记为第一,第二和第三的所有结果,而不是第一,第二或第三。

编辑:也许这个问题不太清楚。它更像是一个SQL问题,因为与公司关联的每个标记都是CompanyTag表中的单独条目。因此,我不认为可以通过更改正则表达式来解决它,因为只有我的知识才能根据表中的单个条目进行评估,而不是所有条目连接在一起。

3 个答案:

答案 0 :(得分:1)

我会因为使用正则表达式而尖叫这个问题。

如果您拥有独特的标签和公司以及独特的公司标签组合,您可以轻松搜索标签标题的公司。

OR逻辑:

  SELECT c.* 
    FROM company c 
    JOIN companyTag ct ON ct.companyName = c.name
   WHERE ct.tag IN (:1,:2,:3)
GROUP BY c.name;

AND逻辑:

  SELECT c.* 
    FROM company c 
    JOIN companyTag ct ON ct.companyName = c.name
   WHERE ct.tag IN (:1,:2,:3)
GROUP BY c.name
  HAVING count(*) = 3;

<强>更新

我可能会更进一步,创建一个单独的tag表格(id,title),其title上有一个唯一的companyid name和唯一的companyTag并使(companyId, tagId)多个{{1}}在两个字段中都是唯一的。

答案 1 :(得分:0)

你可以试试这个正则表达式:

^(?=.*first.*)(?=.*second.*)(?=.*third.*).*$

应该检查所有3个条件,firstsecondthird必须出现在字符串中。这些词不必按照一定的顺序排列。

您可以查看regex works on the regex101.com

的方式

答案 2 :(得分:0)

我不确定正则表达式是最好的方法。假设您没有在字段tag中存储多个分隔标记,只需使用in

SELECT c.name, c.description, c.location, c.website, c.categoryName
FROM Company c INNER JOIN
     CompanyTag ct
     ON ct.companyName = c.name
WHERE tag in ($first, $second, $third)

这样做的好处是where子句可以利用索引。

假设您想要公司中的所有代码,请添加group byhaving

SELECT c.name, c.description, c.location, c.website, c.categoryName
FROM Company c INNER JOIN
     CompanyTag ct
     ON ct.companyName = c.name
WHERE tag in ($first, $second, $third)
GROUP BY c.name, c.description, c.location, c.website, c.categoryName
HAVING count(distinct tag) = 3;  -- Note:  "3" here depends on the number of tags

如果您更喜欢正则表达式方法,当然可以使用in来代替where