我拥有世界上最简单的表格,用于查找英国邮政编码的lat / lng值(加载完整的英国邮政编码数据):
CREATE TABLE postcodes (
postcode char(7) NOT NULL,
lat double(10,6) NOT NULL,
lng double(10,6) NOT NULL,
KEY postcode (postcode)
)
“邮政编码”字段中的邮政编码在前半部分的末尾有2位数字,或者一个,然后是空格。我认为这个空间对于它们如何匹配(??)的完整性很重要,而且我不想删除表中的空格,因为我还要拔出用于显示目的的邮政编码(我不喜欢我想要一个重复的领域,因为我很挑剔!)。例子:
'LE115AF', 'BS6 5EE', 'W1A 1AA', 'BS216RS', 'M3 1NH'
所以,有些人有空位,有些则没空。大多数是7个字符,有些只有6个。
无论如何,重点是我希望用户能够输入邮政编码查询,包括部分邮政编码,有或没有空格,并且如果他们的输入字符串有效(即他们没有输入完整或部分),总是找到匹配表中不存在的邮政编码。)
到目前为止,我已经完成了这项工作(在PHP的帮助下):
{...} WHERE `postcode` LIKE '" . str_replace(' ','%',$query) . "%' LIMIT 1
这有利于:
但不适用于这些查询:
我猜我需要以某种方式做一些MySQL字符串函数魔法,以便在行的邮政编码字段中有空格,并相应地调整我的WHERE子句逻辑?有人对最佳方法有任何建议吗?理想情况下我也希望:
答案 0 :(得分:5)
创建一个新列,它只是剥离了空格的邮政编码字段,并在其上创建唯一索引。你不应该找到任何重复。这应该让你放心,这个空间真的不重要:)
在剥离输入邮政编码上的空格后,使用 进行查找。
请记住,涉及将字符串函数应用于表的postcode
列的解决方案可能会阻止MySQL使用该列上的任何索引。 (索引基于列中的确切数据,因此,如果您开始将函数应用于该数据,则优化器通常会确定该索引无用。)
如果你确实觉得需要重新格式化,那么最简单的选择就是知道邮政编码的“出站”部分 - 空格之前的部分 - 格式稍有不同,“入站” “部分 - 空间之后的部分 - 始终是一个数字后跟两个字母。
顺便说一下,我发现的格式上最好的资源是the Wikipedia entry。
答案 1 :(得分:1)
您也可以删除数据库级别的空格:
{...} WHERE replace(`postcode`, ' ','') LIKE '" . str_replace(' ','%',$query) . "%' LIMIT 1
答案 2 :(得分:1)
首先,我不认为这个空间很重要。关于Royal Mail web page的描述没有提到空格。对于每个带有我看过的空间的邮政编码,第二组总是3个字符长,所以可能你可以从后面拆分它。网页上说“通常只是一个数字”,所以可能有例外。
如果您愿意预处理查询字符串(就像您在示例中使用php一样),您可以按如下方式解决问题:通过(1)删除所有空格然后将查询后置代码转换为正则表达式(2)在所有字符之间添加?
(即空格的可选匹配)。最后在末尾添加.*
以允许不完整的代码。例子:
W ?1 ?A ?1 ?A ?A.*
。这符合“W1A1AA”和“W1A 1AA”。M ?3 ?1.*
。在此表单中获得查询后置代码后,您可以使用MySQL的REGEXP
运算符进行匹配:
{...} WHERE `postcode` LIKE 'M ?3 ?1.*' LIMIT 1
最后,顺便说一下,将' '
替换为%
的伎俩有点危险。这种方式BS6 5
将匹配BS6 456
,因为%
会匹配4
。
答案 3 :(得分:0)
您可以通过拆分所有字母来查询。
WHERE `postcode` LIKE '" . implode("%", str_split("W1A1AA")) . "%' LIMIT 1
因为你正在查询一个有限长度的字段,所以不应该产生太多的误报,你可以在检索后通过代码中的 likeness 进行排序(我假设这是为了一个自动完成)。表现应该不好。
答案 4 :(得分:0)
马特的解决方案运作良好。但是,我仍然需要允许用户在他们的查询中专门有一个空格,并处理它,即:
所以,我的增强解决方案(解决了上述问题):
CREATE TABLE postcodes (
postcode varchar(7) NOT NULL,
postcode_display char(7) NOT NULL,
lat double(10,6) NOT NULL,
lng double(10,6) NOT NULL,
UNIQUE KEY postcode (postcode),
UNIQUE KEY postcode_display (postcode_display)
)
postcode
已删除空格,postcode_display
将其留在..
<?php
if (strlen($query) <= 7 && strpos($query,' ') !== false) { $hasSpace = true; }
?>
...
WHERE `postcode" . ($hasSpace ? '_display' : '') . "` LIKE '" . str_replace(' ',($hasSpace ? '%' : ''),$query) . "%' LIMIT 1
有进一步改进的空间吗?
答案 5 :(得分:0)
我会在表格中为扇区和区域生成新条目,这将消除对LIKE的需求。
LIKE条件不能使用索引,因此需要扫描整个表以获得结果。这很慢,特别是当你有一个170万价值的完整英国邮政编码数据库时。
因此,为'M3'创建一个新条目作为邮政编码。对“M31”执行相同操作,依此类推。对于与这些新编码相对应的纬度/经度值,您可以执行一些基本数学计算所有单个邮政编码的平均位置。
试试这个:
SELECT
SUBSTRING(postcode, 1, LOCATE(' ', postcode) - 1),
AVG(lat),
AVG(long)
FROM
postcodes
GROUP BY
SUBSTRING(postcode, 1, LOCATE(' ', postcode) - 1)
然后,您可以将结果反馈回邮政编码表。