3

名前、住所、idcard、町、通りの5つのフィールドを含むデータベースがあります

次に、1 つのパラメーターを受け入れる PHP クエリがあります。このパラメーターには、好きなフィールドを入力できますが、結果は正確でなければなりません。

たとえば、検索ボックスに john doe skate street と入力すると、名前が John Doe で、Skate Street という通りに住んでいるすべてのレコードが表示されます。

また、名前は SURNAME NAME の順に 1 つのフィールドに格納されることに注意してください (これは必須なので変更できません。変更した方がよいとは言わないでください... 私はそれを知っています :))。明らかに、姓名でも姓名でも、名前を任意の順序で入力できるようにしたいと思います。

私の考えは、最初に入力した最初の 2 つのパラメーターを名前として付けることです。クライアントに、最初の 2 つのパラメーターは名前と姓、または姓と名前でなければならないことを伝えます。名前に続いて、任意の注文属性を好きな順序で入力できます。

これらは受け入れられます:

name surname idcard town street
surname name idcard town street
name surname town idcard street
surname name address street idcard

これらは受け入れられません:

idcard town name surname street
town name surname idcard

クエリが非常に複雑になるという単純な理由 (名前/姓の理由と、それらが同じフィールドにあるため)

あまり複雑にせずに後者を可能にする方法があれば、それも聞きたいです。

この問題について助けていただければ幸いです

よろしくお願いします

4

3 に答える 3

4

求めていると思われる種類の検索は、MySQL などの RDBMS のスイート スポットではありません。また、許容される検索形式を指定することは、かなり特定のドメインでない限り、一般的に使いやすさには適していません。

非常に一般的なものにすると、"Persons Name Fake Street" の 3 つのフィールドを検索するクエリは次のようになります。

SELECT * FROM Users
WHERE (FirstName LIKE "%Persons%"
OR LastName LIKE "%Persons%"
OR Address LIKE "%Persons%")
AND (FirstName LIKE "%Name%"
OR LastName LIKE "%Name%"
OR Address LIKE "%Name%")
AND (FirstName LIKE "%Fake%"
OR LastName LIKE "%Fake%"
OR Address LIKE "%Fake%")
AND (FirstName LIKE "%Street%"
OR LastName LIKE "%Street%"
OR Address LIKE "%Street%")

これにより、指定されたものと一致する詳細を持つメンバーが見つかります。しかし、あまりエレガントではなく、より長いクエリとより多くのフィールドで悪化するだけです. また、非常に非効率的であり、テーブルが長くなるとすぐに苦労します-インデックスを使用できません. また、「最高の」一致を上位に表示するのにも役立ちません (多数の結果がある場合)。

より良い解決策は、関連するユーザーを見つけるために全文インデックスを使用して検索できる別のテーブルを作成することにより、MySQL の全文インデックスを使用することです。私はこの解決策についてあまり知りません。

別のオプションとして、Lucene などの外部インデックス作成ツールを使用することもできます。複雑さが増しますが、フィールドの重み付けなどの追加機能が可能になります。たとえば、名前は住所よりも重要であると見なされる可能性があります。これにより、結果を関連性の高い順に並べることもできます。

正しい解決策は (いつものように) 要件によって異なりますが、これらは調査する価値のあるいくつかのアイデアです。

于 2010-02-01T12:52:58.993 に答える
0

これは完璧とは言えませんが、あなたのデザインも完璧ではありません。

入力パラメータ「namesurnameidcardTown street」をトークン化し、DBのフィールドを連結して、一連のlikeまたは'sを実行します。

psudocode
---------
where
name+address+idcard+town+street like %input_token1% or
name+address+idcard+town+street like %input_token2% or
...
name+address+idcard+town+street like %input_token5%
于 2010-02-01T12:57:06.493 に答える
0

正規表現を使用して単語を分割し、それらを Person テーブルに参加できる一時テーブルに入れようとします。

正規表現は次のようになります

preg_match_all('/(\S+)*\s+/im', $input, $value, PREG_PATTERN_ORDER);
for ($i = 0; $i < count($value[0]); $i++) {
    # Matched text = $result[0][$i];
}

結果を見つけるスクリプトは、SQL Server では次のようになります。私は MySQL の代替案を思い付くのに十分な MySQL の知識を持っていませんが、アイデアを得る必要があります

アイデアの要点は、検索するすべての列で入力テーブルと結合することです。このwhere句は、入力値があるため、入力値が少なくとも列の数で見つかるという事実を処理します。

DECLARE @Table TABLE (Name VARCHAR(20), Surname VARCHAR(20), Address VARCHAR(20), IDCard VARCHAR(20), Town VARCHAR(20), Street VARCHAR(20))
DECLARE @Inputs TABLE (Value VARCHAR(32))

INSERT INTO @Table VALUES ('Doe', 'John', 'Dontknow', 'Dontknow', 'US', 'Skate')
INSERT INTO @Inputs VALUES ('%John%')
INSERT INTO @Inputs VALUES ('%Doe%')
INSERT INTO @Inputs VALUES ('%Skate%')

SELECT  t.*
FROM    @Table t
        LEFT OUTER JOIN @Inputs i_name ON t.Name LIKE i_name.Value     
        LEFT OUTER JOIN @Inputs i_surname ON t.SurName LIKE i_surname.Value        
        LEFT OUTER JOIN @Inputs i_address ON t.Address LIKE i_address.Value
        LEFT OUTER JOIN @Inputs i_idcard ON t.IDCard LIKE i_idcard.Value
        LEFT OUTER JOIN @Inputs i_town ON t.Town LIKE i_town.Value
        LEFT OUTER JOIN @Inputs i_street ON t.Street LIKE i_street.Value
        CROSS APPLY (SELECT inputCount = COUNT(*) FROM @Inputs) cnt
WHERE   cnt.inputCount <= 
          CASE WHEN i_name.Value IS NULL THEN 0 ELSE 1 END
          + CASE WHEN i_surname.Value IS NULL THEN 0 ELSE 1 END
          + CASE WHEN i_address.Value IS NULL THEN 0 ELSE 1 END
          + CASE WHEN i_idcard.Value IS NULL THEN 0 ELSE 1 END
          + CASE WHEN i_town.Value IS NULL THEN 0 ELSE 1 END
          + CASE WHEN i_street.Value IS NULL THEN 0 ELSE 1 END
于 2010-02-01T13:37:07.127 に答える