【问题标题】:MySQL - How can I perform this string search?MySQL - 如何执行此字符串搜索?
【发布时间】:2015-03-12 13:24:40
【问题描述】:

我有一张表,其中包含 37 列、各种类型、INT 和 VARCHARS 以及 2 个 LONGTEXT 列。客户端希望通过搜索来搜索表并找到匹配的行。

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

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 

此代码在没有明显错误的情况下执行,但由于它始终不返回任何结果而失败,如返回 0 个字段。我不明白为什么,从最初的角度来看,

3) 因此,通过对操作系统的一些研究,我发现使用 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 中的代码总是返回零行?

干杯

附加工作:

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

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

然而这会返回一个结果,但结果总是表的最后一行。这行不通。

解决方案 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 ";

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

i) 搜索没有 CONCAT 列或

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

请分享!!

【问题讨论】:

  • @Borr 感谢格式化 :)

标签: mysql string search


【解决方案1】:

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

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

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

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

参考文档

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

【讨论】:

  • 哈哈,是的,我会接受你的回答我只是在做一些关于 CONCAT_WS 的背景知识,尽管 - 正如你所说 - CONCAT 对我来说似乎也有些粗糙,我正在查找它们的性能问题。但如果这是唯一可行的解​​决方案,它就必须这样做:)。
  • 经过深思熟虑,明天我会接受这个答案,给这个问题一些时间来提出非 CONCAT 的解决方案。不过谢谢。
【解决方案2】:

一种相当丑陋的方法是

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('%',?,'%')

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

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

警告: 请注意,如果您的列之一包含 null 值,此 CONCAT 可能会失败,因为这样整个 CONCAT 将返回 null!

【讨论】:

  • 嗯,这很难看,但我会构建它,看看它是否有效。谢谢你。是的,所有搜索到的字段都不会是 NULL 值。
  • 如果在字符串之间找到搜索查询说“nd eb”,例如 MemSkype = “nend” 和 MemLinkIn = “ebbe”,那么它会返回误报吗?这是一个不太可能的情况,但有可能吗?
  • 是的,这当然是可能的。所以@ravinder 的答案更好,因为它使用分隔符来消除这个问题。
猜你喜欢
  • 2019-09-08
  • 2023-03-13
  • 1970-01-01
  • 2011-12-16
  • 2019-05-06
  • 1970-01-01
  • 2013-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多