0

英国の郵便番号の緯度/経度の値を検索するための、世界で最も単純なテーブルがあります (完全な英国の郵便番号データが読み込まれています)。

CREATE TABLE postcodes (
  postcode char(7) NOT NULL,
  lat double(10,6) NOT NULL,
  lng double(10,6) NOT NULL,
  KEY postcode (postcode)
)

「郵便番号」フィールドの郵便番号は、前半の最後の 2 桁、または 1 桁とスペースのいずれかです。それらがどのように一致するかの完全性にとってスペースは重要だと思います(??)。さらに、表示目的で郵便番号も引き出しているため、テーブル内のスペースを削除したくありません(そして、私は私はうるさいので、重複したフィールドは必要ありません!)。例:

'LE115AF', 'BS6 5EE', 'W1A 1AA', 'BS216RS', 'M3 1NH'

したがって、スペースがあるものとないものがあります。ほとんどは全体で 7 文字ですが、6 文字しかないものもあります。

とにかく、ポイントは、スペースの有無にかかわらず、部分的な郵便番号を含む郵便番号クエリをユーザーが入力できるようにして、入力文字列が有効な場合は常に一致するものを見つけられるようにすることです (つまり、郵便番号の全部または一部を入力しないでください)。テーブルには存在しません)。

これは私がこれまで行ってきた方法です(PHPの助けを借りて):

{...} WHERE `postcode` LIKE '" . str_replace(' ','%',$query) . "%' LIMIT 1

これは次の場合に適しています。

  • データベースにスペースを含まない完全な郵便番号
  • スペースが入力され、データベースに対応するスペースがある場合、またはクエリされた部分がスペースが発生する場所の手前で停止する場合の部分的な郵便番号 (たとえば、「W1A」は「W1A 1AA」と一致し、「M3 1」は「M3 1AR」と一致します) 」など)。

ただし、次のクエリでは機能しません。

  • 「W1A1AA」は「W1A 1AA」と一致する必要があります
  • 「BS65EE」は「BS6 5EE」と一致する必要があります
  • 「BS65」は、データベースの最初の「BS6 5%」郵便番号、つまり「BS6 5AA」と一致する必要があります。
  • 「M31」も「M3 1AR」と一致する必要があります

行の郵便番号フィールドにスペースがあるかどうかを解決するには、MySQL文字列関数の魔法を何らかの方法で実行し、それに応じてWHERE句のロジックを調整する必要があると思いますか? 誰かが最善のアプローチについてアドバイスを受けましたか? 私も理想的にしたい:

  • MySQL ストアド プロシージャを避ける (インライン関数を推奨)
  • PHP部分でもインライン文字列関数だけを行います
4

6 に答える 6

5

スペースを取り除いた郵便番号フィールドだけの新しい列を作成し、一意のインデックスを作成します。重複を見つけるべきではありません。それは、スペースが本当に重要ではないことを安心させるはずです:)

次に、入力郵便番号のスペースを削除した後、それをルックアップに使用します。

テーブルの列に文字列関数を適用することを含むソリューションは、postcodeMySQL がその列のインデックスを使用できなくなる可能性があることに注意してください。(インデックスは列内の正確なデータに基づいているため、そのデータに関数を適用し始めると、オプティマイザーは通常、インデックスが役に立たないと判断します。)

フォーマットを変更する必要があると感じた場合、最も簡単なオプションは、郵便番号の「アウトバウンド」部分 (スペースの前の部分) のフォーマットが少し異なりますが、「インバウンド」部分は - -スペースのの部分 -- は、常に 1 桁の数字の後に 2 つの文字が続きます。

ちなみに、私がこれまでに見つけたフォーマットに関するおそらく最高のリソースは、ウィキペディアのエントリです。

于 2011-03-10T20:39:13.610 に答える
1

まず、スペースは重要ではないと思います。Royal Mailの Web ページの説明には、スペースについての言及はありません。また、私が見たスペースのあるすべての郵便番号では、2 番目のグループは常に 3 文字の長さだったので、おそらく後ろから分割できます。ただし、Web ページには「通常は 1 つの数字のみ」と記載されているため、例外がある場合があります。

クエリ文字列を前処理する場合 (例で php を使用したように)、次のように問題を解決できます: (1) すべてのスペースを削除してから (2) により、クエリのポスト コードを正規表現に変換します。すべての文字の間に追加?(つまり、スペースのオプションの一致)。最後に、.*不完全なコードを許可するために末尾に a を追加します。例:

  • W1A1AAになりW ?1 ?A ?1 ?A ?A.*ます。これは、「W1A1AA」と「W1A 1AA」に一致します。
  • M31になりM ?3 ?1.*ます。

この形式でクエリの郵便番号を取得したら、MySQL のREGEXP演算子を使用して一致させることができます。

{...} WHERE `postcode` LIKE 'M ?3 ?1.*' LIMIT 1

最後に、余談ですが、 ' 'byで置き換えるトリック%は少し危険です。が に一致するため、この方法BS6 5はに一致します。BS6 456%4

于 2011-03-10T20:52:17.333 に答える
1

データベース レベルでもスペースを削除できます。

{...} WHERE replace(`postcode`, ' ','') LIKE '" . str_replace(' ','%',$query) . "%' LIMIT 1
于 2011-03-10T20:32:23.957 に答える
0

すべての文字を分割してクエリを実行できます。

WHERE `postcode` LIKE '" . implode("%", str_split("W1A1AA")) . "%' LIMIT 1

限られた長さのフィールドをクエリしているため、誤検知に関してはそれほど多くの問題が発生することはなく、取得後にコード内で類似性によって並べ替えることができます(これはオートコンプリート用であると想定しています)。パフォーマンスが悪いはずです。

于 2011-03-10T20:30:45.890 に答える
0

マットのソリューションはうまくいきました。ただし、ユーザーがクエリ内に具体的にスペースを持ち、それを処理できるようにする必要がありました。

  • 「M31」は「M31 4AA」と一致する必要がありますが、
  • 「M3 1」は「M3 1AR」と一致する必要があります

したがって、私の強化されたソリューション(上記の問題を解決します):

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

さらに改良する余地はありますか?

于 2011-03-11T09:54:47.653 に答える
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)

その後、結果を郵便番号テーブルに戻すことができます。

于 2013-02-06T11:52:26.920 に答える