MySQL - 如何执行此字符串搜索?

MySQL - How can I perform this string search?

我有一个 table,它有 37 列,各种类型,INT 和 VARCHARS 以及 2 个 LONGTEXT 列。客户希望搜索 table 并找到匹配的行。

但是,我在这方面遇到了麻烦。这是我到目前为止所做的:

1) 我最初的想法是做大量的 OR 查询——但是我推迟了这个,因为我需要提供大约 30 次的搜索数据,这是大量的重复,我敢肯定有比这更好的方法。

代码:

SELECT
  MemberId,
  MemNameTitle,
  MemSName,
  MemFName,
  MemPostcode,
  MemEmail
FROM
  MemberData
WHERE
  MemFName LIKE CONCAT('%',?,'%') OR
  MemSName LIKE CONCAT('%',?,'%') OR
  MemAddr LIKE CONCAT('%',?,'%') OR
  MemPostcode LIKE CONCAT('%',?,'%') OR
  MemEmail LIKE CONCAT('%',?,'%') 
 ...etc...

等等等。这是一组庞大的 OR,而且非常笨拙。

2) 我想我会尝试重新处理它以将所有列放在括号中然后只询问一次查询,我在 SO 上看到了一段类似的代码但不确定它是否正常工作,但它是一个灵感,至少:

    SELECT
      MemberId,
      MemNameTitle,
      MemSName,
      MemFName,
      MemPostcode,
      MemEmail
    FROM
      MemberData 
    WHERE
      (MemNameTitle OR
       MemFName OR
       MemSName OR
       MemAddr OR
       MemPostcode OR
       MemEmail OR
       MemSkype OR
       MemLinkedIn OR
       MemFacebook OR
       MemEmailTwo ...etc...) LIKE CONCAT('%',?,'%')
     GROUP BY
       MemberId 

此代码执行时没有出现明显的错误,但总是失败 returns 没有结果,因为返回了 0 个字段。我不明白为什么,从最初的角度来看,

3) 因此,通过对 OS 的一些研究,我发现了使用 IN 关键字的重新排列,但是从这里 Is it possible to use LIKE and IN for a WHERE statment? 之前的问题来看,它似乎不起作用。

我想得到的是这样的:

SELECT
  MemberId,
  MemNameTitle,
  MemSName,
  MemFName,
  MemPostcode,
  MemEmail
FROM
  MemberData
WHERE
  MemNameTitle,
  MemFName,
  MemSName,
  MemAddr,
  MemPostcode,
  MemEmail,
  MemSkype,
  MemLinkedIn,
  ...etc ...
  MemFax,
  MemberStatus,
  CommitteeNotes,
  SecondAddr,
  SecondAddrPostcode IN (LIKE CONCAT('%',?,'%')  )

这是粗略的语法,但我希望你能理解我想要的想法,我想使用 LIKE % % 子句在许多字段中搜索相同的值。字段有多种 TEXT/VARCHAR 类型。

4) 然后我查看了 MySQL 全文搜索,但这很快就变得毫无用处,因为它只适用于 TEXT 类型而不是 VARCHAR 类型搜索。我考虑过在每次搜索之前将每个 VARCHAR 列更改为 TEXT 列,但我认为这也是相对处理器密集型的,并且对于许多人必须要做的搜索来说似乎不合逻辑?

所以,我没有想法.....你能帮我这样搜索吗?或者建议为什么我的代码尝试 2 总是 returns 零行?

干杯

额外工作:

5) 我一直在考虑重新排列 IN 子句语句并想出了这个:

    SELECT *(lazy typing!) WHERE
     CONCAT('%',?,'%') IN
 (MemNameTitle, 
MemFName, 
MemSName, 
MemAddr, 
MemPostcode, 
MemEmail, 
MemSkype, 
...etc...
    CommitteeNotes,
 SecondAddr,
 SecondAddrPostcode) 
GROUP BY MemberId 

不过这个returns一个结果,而且这个结果永远是table的最后一行。这是行不通的。

解决方案 1:

来自 Ravinder,对所有字段使用 CONCAT_WS - 这适用于我的情况,虽然在我看来确实发现 CONCAT 有点难看,但是哦,好吧。

SELECT * FROM MemberData WHERE
 CONCAT_WS('<*!*>', 
MemNameTitle, MemFName, MemSName, 
MemAddr, MemPostcode, MemEmail, 
MemSkype, MemLinkedIn,
...etc...
MemberStatus, CommitteeNotes, SecondAddr,
 SecondAddrPostcode)
 LIKE CONCAT('%',?,'%') 
GROUP BY MemberId ";

table 最终将有几千行,我有点担心,因为此查询将为每次搜索的 table 上的每一行连接 24 列,这可能很容易变得非常昂贵和低效(即慢),所以如果有人有任何方法

i) 不使用 CONCAT 列进行搜索或

ii) 使该解决方案更快/更高效

请分享!!

一种相当丑陋的方法是

SELECT
  MemberId,
  MemNameTitle,
  MemSName,
  MemFName,
  MemPostcode,
  MemEmail
FROM
  MemberData
WHERE
CONCAT(
  MemNameTitle,
  MemFName,
  MemSName,
  MemAddr,
  MemPostcode,
  MemEmail,
  MemSkype,
  MemLinkedIn,
  ...etc ...
  MemFax,
  MemberStatus,
  CommitteeNotes,
  SecondAddr,
  SecondAddrPostcode) LIKE CONCAT('%',?,'%')

所以您首先连接所有要搜索的列,然后在生成的大字符串中查找您的文本。

但我想您会发现这远非高效和最佳。但是由于您在搜索的开头和结尾使用了 % 符号,所以无论如何您都不能使用任何索引。

警告: 请注意,如果您的其中一列包含空值,此 CONCAT 可能会失败,因为那样整个 CONCAT 将 return null!

有一个变通解决方案。但是我觉得这样太粗糙了,性能可能不会那么好。

where
 concat_ws( "<*!*>", col1, col2, col3, ... ) like concat( '%', ?, '%' )

在这里,我使用 '<*!*>' 作为示例分隔符。
您必须使用模式字符串作为分隔符,您确定

  1. 不是占位符值的一部分或
  2. 当有 2 列或更多列时,它不是生成的字符串的一部分 串联

参考文档

MySQL: CONCAT_WS(separator,str1,str2,...)
它不会跳过空列值,但会跳过 NULL。