对不起,我花了这么长时间才回来——我自私地在那里度假!如果您仍在为此工作:
好的,关于基础知识。假设您有一个名为“place”的表和一个名为“city”的字段。您可以使用“like”运算符对前几个字符进行简单匹配。
select <whatever> from place where city like 'San Fran%';
您可能想忽略大小写,因此“san fran”将匹配 San Francisco。在这种情况下:
select <whatever> from place where upper(city) like upper('San Fran%');
当然在现实生活中你不会硬编码“San Fran”,它是一个运行时参数。
在城市上创建一个索引,这将非常快。如果您使用“上”使其不区分大小写,则在上(城市)上创建索引。
好的,所以您还想处理另一种情况:缩写,例如旧金山的“SF”。
你没有说你正在使用什么风格的 SQL。如果它支持函数,您可以编写一个函数,该函数将形成任何名称的缩写。该函数可以使用子字符串(或您的 SQL 具有的任何等效项——我认为这些函数不是很标准)扫描名称的字符,查找空格,然后拉出第一个字符,然后是空格后面的每个字符,然后返回。假设您将此函数称为“abbreviate()”。那么查询将是:
select <whatever> from place where upper(city) like concat(@city,'%') or abbreviate(city) = @city;
(上面是它在 MS SQL Server 中的样子,其中参数的名称以“@”开头。)
然后,您将在 upper(city) 和 abbreviate(city) 上创建索引以保持快速。
如果您想比这更灵活,那么,我认为没有任何办法可以考虑您要处理的每个案例。就像如果您希望用户能够输入“frisco”并找到 San Francisco,或“vegas”获得 Las Vegas,您可以在城市名称中的任何位置搜索输入的字符串,即“city like '%frisco%' ”。但这有两个大问题。一,我认为你会得到很多错误的点击,其中很多可能对用户来说相当神秘。像输入“san”,得到的不仅仅是“San Francisco”和“San Diego”,还有“Thousand Oaks, California”。(看到 thouSANd 中的“san”吗?)第二,当 LIKE 子句以通配符开头时,SQL 不能使用索引,因此这样的搜索意味着每次都进行全文件扫描。
如果您希望使用多种变体,我认为您需要一个昵称表。在这种情况下,我会创建一个不包含地点名称的“地点”表。然后创建一个 place_name 表,其中包含您要接受的名称的所有变体。在 place_name 和 place 之间创建多对一关系。在 place_name 中包含一个字段,用于标识哪个是“主名称”。然后查询变为:
select n2.name, p.place_id, <whatever>
from place_name n
join place p on n.place_id=p.place_id
join place_name n2 on n2.place_id=n.place_id and n2.is_primary=1
where n.name like concat(@name,'%') or abbrev(n.name)=@name;
对于只有一个名称的地点,该地点只有一个 place_name 记录。
我说将所有名称放在 place_name 表中,而不仅仅是备用名称,这样您只需搜索一个表而不是两个表即可找到该地点。它简化了人类读者和数据库引擎的查询。