data1 に「キーワード」を含む行を取り出す場合はこのように書いているのですが
$result = pg_query(SELECT data1, data2, data3, FROM table WHERE data1 ~'キーワード'");
data1, data2, data3のどこで良いので「キーワード」を含む行を取り出す場合はどのように書くのでしょうか?
また、data1, data2, data3のどこでも良いので「キーワード1」と「キーワード2」の両方を含む場合、
また、data1, data2, data3のどこでも良いので「キーワード1」か「キーワード2」のどちらかを含む場合も教えてください。
よろしくお願いします。
このような検索には定石がありますので、それに従って素直に実装した方が良いと思います。
(語句の連結などで無理やり対応すると、完全一致の際などにINDEXが使われないなどの悪影響が出ます。)
また、私はPostgreSQLには詳しくないのですが、DBの移行の可能性なども考慮し、独自関数に頼らず、ややこしい処理はプログラム(PHP)側で行い、SQLは一般的なものにしておいた方が良いでしょう。
簡単なサンプルを書いてみましたので、確認してみてください。
キーワードの数に依存せずに、適切なSQLを生成できます。
(ソースの見通しをよくするためにpg_escape_stringなどは行っておりませんので、実際に使う際には適切な前処理をほどこしたデータのみDB検索に使うようにしてください。)
<?php /* $_POST["search_words"]に半角スペース区切りの文字が入っていることを想定 以下では代わりに$post_search_wordsという変数を用いる */ $post_search_words = "abc def ghi"; $vague_flag = 0; // $vague_flagで完全一致か曖昧検索かを分ける ( 0:完全,1:曖昧 ) $andor_flag = 0; // $andor_flagでAND検索かOR検索かを分ける ( 0:AND,1:OR ) /* preg_splitを用い、検索語句を半角スペースごとに分解 $keywords配列に代入 */ $keywords = preg_split("/\s/",$post_search_words); // $andor_flagの値によってANDを使うか、ORを使うかを分ける if ($andor_flag == 0 ){ $andor = "AND "; } else if ($andor_flag == 1 ){ $andor = "OR "; } else { print "エラーです。"; exit; } // $vague_flagの値によって完全一致か曖昧検索かを分ける switch ($vague_flag) { case 0: $sql = "SELECT data1, data2, data3 FROM table WHERE "; for ($i=0;$i<count($keywords)-1;$i++){ $sql .= "(data1 = '" . $keywords[$i] . "' OR data2 = '" . $keywords[$i] . "' OR data3 = '" . $keywords[$i] . "') " . $andor; } $sql .= "(data1 = '" . $keywords[count($keywords)-1] . "' OR data2 = '" . $keywords[count($keywords)-1] . "' OR data3 = '" . $keywords[count($keywords)-1] . "')"; print $sql; break; case 1: $sql = "SELECT data1, data2, data3 FROM table WHERE "; for ($i=0;$i<count($keywords)-1;$i++){ $sql .= "(data1 LIKE '%" . $keywords[$i] . "%' OR data2 LIKE '%" . $keywords[$i] . "%' OR data3 LIKE '%" . $keywords[$i] . "%') " . $andor; } $sql .= "(data1 LIKE '%" . $keywords[count($keywords)-1] . "%' OR data2 LIKE '%" . $keywords[count($keywords)-1] . "%' OR data3 LIKE '%" . $keywords[count($keywords)-1] . "%')"; print $sql; break; } ?>
$vague_flag、$andor_flagの値を変更することで、出力されるSQLが変わりますので、確認してみてください。
これらのflagは画面上にcheckboxを設置し、その状態によって値を決めると良いと思います。
[参考URL]
参考になれば幸いです。
こちらでいかがでしょう?
>data1, data2, data3のどこでも良いので「キーワード1」と「キーワード2」の両方を含む場合
$sql = "SELECT data1, data2, data3 FROM table ";
$sql = $sql." WHERE (data1 like '%キーワード1%'";
$sql = $sql." OR data2 like '%キーワード1%'";
$sql = $sql." OR data3 like '%キーワード1%')";
$sql = $sql." OR (data1 like '%キーワード2%'";
$sql = $sql." OR data2 like '%キーワード2%'";
$sql = $sql." OR data3 like '%キーワード2%')";
$result = pg_query($sql);
>data1, data2, data3のどこでも良いので「キーワード1」か「キーワード2」のどちらかを含む場合
$sql = "SELECT data1, data2, data3 FROM table ";
$sql = $sql." WHERE data1 like '%キーワード1%'";
$sql = $sql." OR data2 like '%キーワード1%'";
$sql = $sql." OR data3 like '%キーワード1%'";
$sql = $sql." OR data1 like '%キーワード2%'";
$sql = $sql." OR data2 like '%キーワード2%'";
$sql = $sql." OR data3 like '%キーワード2%'";
$result = pg_query($sql);
ありがとうございます
>data1, data2, data3のどこでも良いので「キーワード1」と「キーワード2」の両方を含む場合
$sql = "SELECT data1, data2, data3 FROM table ";
$sql = $sql." WHERE (data1 like '%キーワード1%'";
$sql = $sql." OR data2 like '%キーワード1%'";
$sql = $sql." OR data3 like '%キーワード1%')";
$sql = $sql." OR (data1 like '%キーワード2%'";
↑この行も「OR」で良いのですか?
$sql = $sql." OR data2 like '%キーワード2%'";
$sql = $sql." OR data3 like '%キーワード2%')";
$result = pg_query($sql);
>data1, data2, data3のどこでも良いので「キーワード1」か「キーワード2」のどちらかを含む場合
こちらはわかりました。
ちなみに
>data1, data2, data3のどこでも良いので「キーワード1」と「キーワード2」の両方を含む場合
というのは
data1.data2.data3 like '%キーワード1%|%キーワード2%'
というようなことはできないのでしょうか?
一つ一つ書くしかないのでしょうか?
サイトで使う際に複数のキーワードを入力でき、AND検索できるようにした際、
仮に5つキーワードを入力されると、上記のような感じで5回繰り返さなければならないのでしょうか?
?ばかりですがよろしくお願いします。
再回答、失礼します。
たとえば、data1 の中のデータを考えた場合、
「aaaaキーワード1bbbbキーワード2cccc」
という文字列や、
「aaaaキーワード2bbbbキーワード1cccc」
という文字列の場合も対象にならなくてはなりませんよね。
ですので、
data1.data2.data3 like '%キーワード1%|%キーワード2%'
という風な記述では対応できないと思われます。
ちなみに、私、PHPもPostgrSQLも全く判らないのですが、
「|」という演算子?を使用した書き方は、無いと思います。
>仮に5つキーワードを入力されると、上記のような感じで5回繰り返さなければならないのでしょうか?
そうですね。面倒ですが、繰り返しになると思います。
なお、like演算子を使わないで済むのであれば、
data1 in ('キーワード1','キーワード2')
のように記述可能です。
これは、
data1 = 'キーワード1'
OR data1 = 'キーワード2'
と同じです。
※「一致総数の取得と検索を同時に・・・」のご質問ですが、
SELECT COUNT(1) AS REC_CNT FROM table;
で、レコード件数を取得し、
SELECT data1, data2, data3, FROM table WHERE title Like '%キーワード%' LIMIT 20 OFFSET 0"
で、レコードセットを取得
という風に、面倒ですが2段階で取得する方法しかないと思います。
ありがとうございます
今本を見ながら勉強中なのですがPostgresならば「~」を使うと正規表現のパターンマッチが使えるので「~'キーワード1|キーワード2'」でできるそうです。
間違えでしたらどなたかご指摘下さい。
> ※「一致総数の取得と検索を同時に・・・」のご質問ですが、
面倒ですが2段階で取得する方法しかないと思います。
やはり面倒な感じなのですね
再々回答で、すみません。汗
>↑この行も「OR」で良いのですか?
ご指摘のとおり、「AND」ですね。
申し訳ありませんでした。
いえいえ、念のための確認なのでお気になさらないで下さい。
http://homepage2.nifty.com/sak/w_sak3/doc/sysbrd/sak3sql.htm
厳密な意味では難しいですが、むりやり文字列を連結するやり方でやるとすると、
$sql = 'SELECT data1 || data2 || data3 AS data123 FROM table '
$sql .= 'WHERE data123 like "%キーワード1%" '
$sql .= 'OR data123 like "%キーワード2%"'
というのもありかもしれません。
●文字列の連結は || です。
●$sql .= は $sql = $sql. と同じ意味です。
欠点は、data1 = "キー” data2 = "ワード” といった場合にも"キーワードにヒットしてしまう点です。
これを回避するには、連結時にキーワードには使われない文字をはさむ等で出来る気はします。
が、正道ではないかな。
ありがとうございます。
「||」で繋げられるんですね。
> $sql .= は $sql = $sql. と同じ意味
これはphpですよね。よく使ってます。
> data1 = "キー” data2 = "ワード” といった場合にも"キーワードにヒットしてしまう
確かにそうですね。
> これを回避するには、連結時にキーワードには使われない文字をはさむ等で出来る気はします。
> が、正道ではないかな。
検索が早ければ個人的には問題ない気もするのですが。。。
このような検索には定石がありますので、それに従って素直に実装した方が良いと思います。
(語句の連結などで無理やり対応すると、完全一致の際などにINDEXが使われないなどの悪影響が出ます。)
また、私はPostgreSQLには詳しくないのですが、DBの移行の可能性なども考慮し、独自関数に頼らず、ややこしい処理はプログラム(PHP)側で行い、SQLは一般的なものにしておいた方が良いでしょう。
簡単なサンプルを書いてみましたので、確認してみてください。
キーワードの数に依存せずに、適切なSQLを生成できます。
(ソースの見通しをよくするためにpg_escape_stringなどは行っておりませんので、実際に使う際には適切な前処理をほどこしたデータのみDB検索に使うようにしてください。)
<?php /* $_POST["search_words"]に半角スペース区切りの文字が入っていることを想定 以下では代わりに$post_search_wordsという変数を用いる */ $post_search_words = "abc def ghi"; $vague_flag = 0; // $vague_flagで完全一致か曖昧検索かを分ける ( 0:完全,1:曖昧 ) $andor_flag = 0; // $andor_flagでAND検索かOR検索かを分ける ( 0:AND,1:OR ) /* preg_splitを用い、検索語句を半角スペースごとに分解 $keywords配列に代入 */ $keywords = preg_split("/\s/",$post_search_words); // $andor_flagの値によってANDを使うか、ORを使うかを分ける if ($andor_flag == 0 ){ $andor = "AND "; } else if ($andor_flag == 1 ){ $andor = "OR "; } else { print "エラーです。"; exit; } // $vague_flagの値によって完全一致か曖昧検索かを分ける switch ($vague_flag) { case 0: $sql = "SELECT data1, data2, data3 FROM table WHERE "; for ($i=0;$i<count($keywords)-1;$i++){ $sql .= "(data1 = '" . $keywords[$i] . "' OR data2 = '" . $keywords[$i] . "' OR data3 = '" . $keywords[$i] . "') " . $andor; } $sql .= "(data1 = '" . $keywords[count($keywords)-1] . "' OR data2 = '" . $keywords[count($keywords)-1] . "' OR data3 = '" . $keywords[count($keywords)-1] . "')"; print $sql; break; case 1: $sql = "SELECT data1, data2, data3 FROM table WHERE "; for ($i=0;$i<count($keywords)-1;$i++){ $sql .= "(data1 LIKE '%" . $keywords[$i] . "%' OR data2 LIKE '%" . $keywords[$i] . "%' OR data3 LIKE '%" . $keywords[$i] . "%') " . $andor; } $sql .= "(data1 LIKE '%" . $keywords[count($keywords)-1] . "%' OR data2 LIKE '%" . $keywords[count($keywords)-1] . "%' OR data3 LIKE '%" . $keywords[count($keywords)-1] . "%')"; print $sql; break; } ?>
$vague_flag、$andor_flagの値を変更することで、出力されるSQLが変わりますので、確認してみてください。
これらのflagは画面上にcheckboxを設置し、その状態によって値を決めると良いと思います。
[参考URL]
参考になれば幸いです。
なるほど!!
こういうやり方が「定石」なのですね。
phpでキーワード数分繰り返してSQLを作るのですね。
こういう「定石」が知りたかったのです。
ありがとうございました。
なるほど!!
こういうやり方が「定石」なのですね。
phpでキーワード数分繰り返してSQLを作るのですね。
こういう「定石」が知りたかったのです。
ありがとうございました。