2

MySQL データベースの「アドレス」テーブルにアドレスがあります。このテーブルには、住所 ID 列と、名前、1 行目、2 行目、郊外、州、郵便番号など、通常の住所関連の列が含まれています。多くのフィールドでは NULL が許可されます。

これは、クライアント側の Web ベースのインターフェイスで使用されます。ユーザーは、アドレスの一部をテキスト ボックスに入力することで、テーブルからアドレスを検索して選択できます。一致が表示され、ユーザーは 1 つを選択できます。

空港はオーストラリアの「str」のためにリストされています

テキスト ボックス内の用語は、スペースで区切られた一連の検索用語として扱われ、選択のために表示されるには、各用語がいずれかのアドレス フィールドに存在する必要があります。

これで、一致する検索語が 2 つになりました...

私はこれのためのいくつかの実装方法の間で引き裂かれています:

現在の方法:

  1. ページの読み込み時に、非同期 HTTP リクエスト (「AJAX」) を使用して、きれいにフォーマットされたリスト (空白のフィールドを考慮してすべてのフィールドを 1 行にまとめたもの) ですべてのアドレスを取得します。
  2. テキスト ボックスが入力を受け取るたびに、jQuery を使用して、このリスト内の一致を見つけて表示します。

このアプローチの利点は、送信する必要がある単純なクエリは 1 つだけであり、検索はクライアント側で行われるため、検索フィールドに入力してから応答を確認するまでに遅延がないことです (ただし、これはうまく拡張できない場合があります。以下を参照してください)。 . また、複雑な SQL 検索の必要性を回避します (これは嫌いではありません。概念実証として何かを実装したかっただけで、この方法の方が高速でした)。

欠点はもちろん、ページが読み込まれるときにページがすべてのアドレスを取得する必要があり、データベースが何千ものアドレスを格納することになる可能性が高いことです。

もう 1 つの方法は、ユーザーがテキスト ボックスに入力するたびに HTTP 要求を送信することです。これにより、SQL を使用したテーブルの検索に一致するアドレスが返されます。より多くのリクエストとより大きな遅延が必要ですが、毎回アドレスのサブセットを取得して転送するだけで済みます。必要に応じて、最小期間の長さとポーリング頻度を簡単に調整できます。

これのSQL側を実装する最良の方法について疑問に思っています...

検索可能なすべてのアドレス列を連結するビューを作成し、「concatcolumn LIKE '%term1%' AND concatcolumn LIKE '%term2%' AND concatcolumn LIKE '%termN%'」の行に沿って WHERE 句を含むクエリを使用するのが最善でしょうか? "?

アイデアや提案は大歓迎です。

4

2 に答える 2

2

私はかなり満足している解決策にたどり着きました。

最初に、連結された検索可能な住所フィールドを含むビューを作成しました。

CREATE VIEW address_concat AS
SELECT address_id, CONCAT_WS(' ', address_name, address_line_1, address_line_2, suburb, postcode, state, country) AS full_address
FROM address

検索文字列を含むリクエストが受信されると、PHP でそれを解析し、ビューを使用して一致を見つけます (次のコードはクリーンアップされ、無関係なものが削除されます - データはサニタイズされます):

$terms = explode(' ', preg_replace('/\s+/', ' ', $_GET['find_address'])); //get array of terms  
$where = " WHERE full_address LIKE '%".implode("%' AND full_address LIKE '%", $terms)."%' "; //turn array into WHERE clause

//query database to find matches
$result = $db->query("SELECT a.* FROM address a JOIN address_concat ac ON a.address_id = ac.address_id ".$where." ORDER BY IFNULL(IF(address_name = '', NULL, address_name), address_line_1)");

if ($result->num_rows > 0)
{       
    //construct output
    $output = '<ul>';

    while ($row = $result->fetch_assoc())
        $output .= '<li val_id="'.$row['address_id'].'">'.make_address(...).'</li>';

    $output .= '</ul>';
}
else
    $output = '<p>No matches found.</p>';

クライアント側では、他の 質問からの知恵を利用して、入力を一時停止した後にのみクエリを実行できるようにしました。

var typingTimer;

$('input#filterbox').bind('input', function () 
{
    var textfield = $(this);

    //code to hide/show "clear text field" box eliminated, etc

    clearTimeout(typingTimer);
    typingTimer = setTimeout(function () {doFilterUpdate(textfield);}, 750);

});

function doFilterUpdate (target)
{
    if (target.val().length >= 3)
        $('div#resultlist').load('inc/ajax.php?find_address=' + encodeURIComponent(target.val()));
    else
        $('div#resultlist').html('');
}

ビューの作成が必要かどうか、または WHERE 句で CONCAT_WS を使用するアドレス テーブルにクエリを作成するよりも効率的かどうかはまだわかりません...ただし、クエリははるかに簡単になります :P

于 2013-03-06T02:13:24.263 に答える
0

検索する前にアドレスを戻さないでください。ユーザーは結果を返すのにかかる秒数を気にせず、読み込みGIFを使用して、ajax呼び出し中に何かが起こっていることを示します。

次のようなことをします:

SELECT columns
FROM   table
WHERE     searchterm LIKE '%' + column1 + '%'
       OR searchterm LIKE '%' + column2 + '%'
       OR searchterm LIKE '%' + column3 + '%'

REPLACEまた、この関数を使用して、スペース、コンマ、およびフルストップを削除したくなるでしょう。

REPLACE(REPLACE(REPLACE(searchterm,' ',''),',',''),'.','') LIKE '%' + column1 + '%'

また、クエリの終了後にキーワードLIMITを使用して返される結果の数に制限を設けたいと思うでしょう。

于 2013-03-05T07:21:21.153 に答える