PHP+PostgrSQLについて教えてください。


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」のどちらかを含む場合も教えてください。

よろしくお願いします。

回答の条件
  • 1人5回まで
  • 登録:2006/05/29 22:34:45
  • 終了:2006/05/30 19:57:14

ベストアンサー

id:bonlife No.5

回答回数421ベストアンサー獲得回数752006/05/30 19:41:52

ポイント60pt

このような検索には定石がありますので、それに従って素直に実装した方が良いと思います。

(語句の連結などで無理やり対応すると、完全一致の際などに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]

参考になれば幸いです。

id:worldtravel

なるほど!!

こういうやり方が「定石」なのですね。

phpでキーワード数分繰り返してSQLを作るのですね。

こういう「定石」が知りたかったのです。

ありがとうございました。

2006/05/30 19:54:26

その他の回答(4件)

id:llusall No.1

llusall回答回数505ベストアンサー獲得回数612006/05/29 23:01:56

ポイント10pt

こちらでいかがでしょう?

>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);

id:worldtravel

ありがとうございます

>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回繰り返さなければならないのでしょうか?

?ばかりですがよろしくお願いします。

2006/05/29 23:13:21
id:llusall No.2

llusall回答回数505ベストアンサー獲得回数612006/05/29 23:48:32

ポイント10pt

再回答、失礼します。

たとえば、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段階で取得する方法しかないと思います。

id:worldtravel

ありがとうございます

今本を見ながら勉強中なのですがPostgresならば「~」を使うと正規表現のパターンマッチが使えるので「~'キーワード1|キーワード2'」でできるそうです。

間違えでしたらどなたかご指摘下さい。

> ※「一致総数の取得と検索を同時に・・・」のご質問ですが、

面倒ですが2段階で取得する方法しかないと思います。

やはり面倒な感じなのですね

2006/05/30 00:02:49
id:llusall No.3

llusall回答回数505ベストアンサー獲得回数612006/05/29 23:53:33

再々回答で、すみません。汗

>↑この行も「OR」で良いのですか?

ご指摘のとおり、「AND」ですね。

申し訳ありませんでした。

id:worldtravel

いえいえ、念のための確認なのでお気になさらないで下さい。

2006/05/29 23:57:48
id:Mook No.4

Mook回答回数1313ベストアンサー獲得回数3922006/05/30 00:33:41

ポイント20pt

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 = "ワード” といった場合にも"キーワードにヒットしてしまう点です。

これを回避するには、連結時にキーワードには使われない文字をはさむ等で出来る気はします。

が、正道ではないかな。

id:worldtravel

ありがとうございます。

「||」で繋げられるんですね。

> $sql .= は $sql = $sql. と同じ意味

これはphpですよね。よく使ってます。

> data1 = "キー” data2 = "ワード” といった場合にも"キーワードにヒットしてしまう

確かにそうですね。

> これを回避するには、連結時にキーワードには使われない文字をはさむ等で出来る気はします。

> が、正道ではないかな。

検索が早ければ個人的には問題ない気もするのですが。。。

2006/05/30 00:48:01
id:bonlife No.5

回答回数421ベストアンサー獲得回数752006/05/30 19:41:52ここでベストアンサー

ポイント60pt

このような検索には定石がありますので、それに従って素直に実装した方が良いと思います。

(語句の連結などで無理やり対応すると、完全一致の際などに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]

参考になれば幸いです。

id:worldtravel

なるほど!!

こういうやり方が「定石」なのですね。

phpでキーワード数分繰り返してSQLを作るのですね。

こういう「定石」が知りたかったのです。

ありがとうございました。

2006/05/30 19:54:26

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません