MySQL以随机顺序查找包含字符的字符串

时间:2015-12-03 11:25:18

标签: mysql

我有一个MySQL表,其中列为主键,列为“单词”。 “单词”包含不同的术语,例如“表”或“汽车”或“学校”。

现在,您可以在此MySQL表中以随机顺序搜索字符。如果输入“hqaletabzu”,MySQL应该只显示“table”,因为它是唯一可以用这个字符构建的术语。

“lohcsautmve”之后的搜索显示“自动化”和“学校”。

有人知道如何在MySQL中表达这一点吗?

2 个答案:

答案 0 :(得分:1)

MySQL非常不适合这项任务。

你可以用

完成
 WHERE col LIKE '%t%'
   AND col LIKE '%a%'
   AND col LIKE '%b%'
   AND col LIKE '%l%'
   AND col LIKE '%e%'

但表现会很糟糕。

答案 1 :(得分:1)

我能想到以任何效率实现这一目标的唯一方法是将表格中的字和被搜索的字符串分成单独存储的单个字母。使用尽可能少的DB更改将单词存储为以逗号分隔的字母列表,但最好将每个字母存储在另一个表中,第一个表上每行每个字母一行

例如第一个想法。

MyTable
id  word        letters             letter_count
1   Table       t,a,b,l,e           5
2   School      s,c,h,o,l           5
3   Automotive  a,u,t,o,m,i,v,e     8

下面的sql

SELECT MyTable.id, MyTable.word 
FROM MyTable
WHERE (IF(FIND_IN_SET('l', MyTable.letters), 1, 0)
+ IF(FIND_IN_SET('o', MyTable.letters), 1, 0)
+ IF(FIND_IN_SET('h', MyTable.letters), 1, 0)
+ IF(FIND_IN_SET('c', MyTable.letters), 1, 0)
+ IF(FIND_IN_SET('s', MyTable.letters), 1, 0)
+ IF(FIND_IN_SET('a', MyTable.letters), 1, 0)
+ IF(FIND_IN_SET('u', MyTable.letters), 1, 0)
+ IF(FIND_IN_SET('t', MyTable.letters), 1, 0)
+ IF(FIND_IN_SET('m', MyTable.letters), 1, 0)
+ IF(FIND_IN_SET('v', MyTable.letters), 1, 0)
+ IF(FIND_IN_SET('e', MyTable.letters), 1, 0)) >= MyTable.letter_count

这不是使用索引,但我认为比使用LIKE快一点。但仍然很慢而且不那么好

更灵活,并且处理多达100个字母的单词,你可以做这样的事情。仍然讨厌阅读,并且不会很快,但很容易在你正在寻找的混乱信件中徘徊(未经测试,请原谅任何错别字): -

SELECT MyTable.id, MyTable.word, MyTable.letter_count, COUNT(*) as letter_match
FROM MyTable
INNER JOIN
(
    SELECT SUBSTR('hqaletabzu', tens.aCnt * 10 + units.aCnt + 1, 1) AS aLetter
    FROM
    (SELECT 1 aCnt UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0) units
    CROSS JOIN
    (SELECT 1 aCnt UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0) tens
    WHERE LENGTH('hqaletabzu') > (tens.aCnt * 10 + units.aCnt)
) sub1
ON FIND_IN_SET(aLetter, MyTable.letters)
GROUP BY MyTable.id, MyTable.word, MyTable.letter_count
HAVING letter_match >= letter_count

修改

使用字母表进一步建议。这应该更快,就像设置索引一样,可以利用它们。

演示表: -

CREATE TABLE MyTable
(
    id  INT,
    word    VARCHAR(255)
);


INSERT INTO MyTable (id, word) VALUES
(1, 'Table'),
(2, 'School'),
(3, 'Automotive');


CREATE TABLE MyTableLetters
(
    id  INT,
    mytable_id  INT,
    letter  CHAR(1)
);

INSERT INTO MyTableLetters VALUES
(NULL, 1, 't'),
(NULL, 1, 'a'),
(NULL, 1, 'b'),
(NULL, 1, 'l'),
(NULL, 1, 'e'),
(NULL, 2, 's'),
(NULL, 2, 'c'),
(NULL, 2, 'h'),
(NULL, 2, 'o'),
(NULL, 2, 'l'),
(NULL, 3, 'a'),
(NULL, 3, 'u'),
(NULL, 3, 't'),
(NULL, 3, 'o'),
(NULL, 3, 'm'),
(NULL, 3, 'i'),
(NULL, 3, 'v'),
(NULL, 3, 'e');

使用这些表,以下SQL将为您提供所需的内容: -

SELECT MyTable.id, MyTable.word, COUNT(MyTableLetters.id) AS MyTableLetters_count, COUNT(aLetter) as letter_match
FROM MyTable
INNER JOIN MyTableLetters ON MyTable.id = MyTableLetters.mytable_id
LEFT OUTER JOIN
(
    SELECT DISTINCT SUBSTR('hqaletabzu', tens.aCnt * 10 + units.aCnt + 1, 1) AS aLetter
    FROM
    (SELECT 1 aCnt UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0) units
    CROSS JOIN
    (SELECT 1 aCnt UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0) tens
    WHERE LENGTH('hqaletabzu') > (tens.aCnt * 10 + units.aCnt)
) sub1
ON sub1.aLetter = MyTableLetters.letter
GROUP BY MyTable.id, MyTable.word
HAVING letter_match >= MyTableLetters_count

请注意,主子查询将每个字母的搜索字母拆分为一行,并删除重复的字母。