我有一个PHP代码片段,它查找MySQL表并返回与给定搜索字符串相关的前6个最接近的匹配,包括精确匹配和部分匹配。 SQL语句是:
SELECT phone, name FROM contacts_table WHERE phone LIKE :ph LIMIT 6;
使用上面的示例,如果分配了:ph
,例如%981%,它将返回包含981的每个条目,例如9819133333,+ 917981688888,9999819999等。但是,是否也可以使用相同的查询返回其值包含在搜索字符串中的所有条目?因此,如果搜索字符串为12345
,则会返回以下所有内容:
答案 0 :(得分:3)
您可以在列号为LIKE
的位置进行查找:
SELECT * FROM `test`
WHERE '123456' LIKE CONCAT('%',`stuff`,'%')
OR `stuff` LIKE '%123456%';
但是,永远不会使用索引,因为索引不能与前面的%
一起使用。
另一种方法是在内存中创建临时表并插入标记化字符串并在临时表上使用JOIN
。这可能比我上面的解决方案慢得多,但它是一个潜在的选择。
答案 1 :(得分:1)
您可以尝试使用动态SQL选项:
SELECT
phone
FROM
contacts_table
WHERE
phone LIKE :ph or
phone = :val1 or
phone = :val2 or
phone = :val3 or
phone = :val4 or
phone = :val5 (so on a so forth)
LIMIT 6;
其中:ph将是您的常规输入(例如%981%),而valX将是标记化输入。
如果您巧妙地进行标记化(例如,如果输入长度为5,则输入标记大小为3或4)将是个好主意。尽量限制令牌的数量以获得更好的性能。
如果您使用PHP,请执行以下操作:
foreach ($phone as getPhoneNumberTokens($input)) {
if ($phone != "") {
$where_args[] = "phone = '$phone'";
}
}
$where_clause = implode(' OR ', $where_args);
答案 2 :(得分:0)
您可以使用三个表格。不过,我实际上并不知道它的性能如何。我没有插入任何东西来测试它。
contact
将包含所有联系人。 token
将包含每个有效令牌。我的意思是当你插入contact
时,你也会对电话号码进行标记,并将每一个标记插入token
表。代币将是独一无二的。凯。那么,您将拥有一个relation
表,其中包含many<->many
和contact
之间的token
关系。
然后,您将获得所有具有与输入电话号码匹配的令牌的联系人。
表格定义:
CREATE TABLE contact (id int NOT NULL AUTO_INCREMENT, phone varchar(16), PRIMARY KEY (id), UNIQUE(phone));
CREATE TABLE token (id int NOT NULL AUTO_INCREMENT, token varchar(16), PRIMARY KEY (id), UNIQUE(token));
CREATE TABLE relation (token_id int NOT NULL, contact_id int NOT NULL);
查询:
可能有更好的方法来编写这个查询(可能通过使用子查询而不是这么多的连接?),但这就是我提出的。
SELECT DISTINCT contact_list.phone FROM contact AS contact_input
JOIN relation AS relation_input
ON relation_input.contact_id = contact_input.id
JOIN token AS all_tokens
ON all_tokens.id = relation_input.token_id
JOIN relation AS relation_query
ON relation_query.token_id = all_tokens.id
JOIN contact AS contact_list
ON contact_list.id = relation_query.contact_id
WHERE contact_input.phone LIKE '123456789'
查询计划:
但是,这在数据库中实际上没有数据,因此如果存在数据,执行计划可能会发生变化。由于eq_ref
和关键用法,我看起来很有希望。
我也让an SQL Fiddle证明了这一点。
注意:
contact
数据库并对其进行标记,然后在查询前插入relation
和token
。相反,您可以使用临时表来查询令牌,然后执行JOIN temp_tokens ON temp_tokens.token = all_tokens.token
...实际上,这可能是您应该做的。但我现在不打算重写这个答案。integer
和phone
使用token
列效果会更好,如果这是您的有效选项。另一种方法,比将所有令牌插入表中只是为了查询更好的方法是使用IN ()
,如:
SELECT DISTINCT contact.phone FROM token
JOIN relation
ON relation.token_id = token.id
JOIN contact
ON relation.contact_id = contact.id
WHERE token.token IN ('123','234','345','and so on')
这是另一个改进的小提琴:http://sqlfiddle.com/#!9/48d0e/2