Привет, это пример моей таблицы, я хочу иметь возможность поиска следующим образом: # mat # godis и иметь возможность получить 2 результата с этими тегами (ID 5 и ID 7)
Это мой PHP-код, и он работает при поиске, например, (Globen), (Globen #mat) и (#mat)
//Strip Search
function selectSearch($search){
$lol = preg_replace('/(^|\s)#(\w*[a-zA-Z_]+\w*)/'," ",$search);
$keywords = explode(" ", preg_replace("/\s+/", " ", $lol));
foreach($keywords as $keyword){
$wherelike[] = "name LIKE '%$keyword%'";
}
$search = implode(" and ", $wherelike);
return $search;
}
//Strip tags
function selectTags($tags){
$str = $tags;
$bits = explode(' ', $str);
$newquery = array();
foreach($bits as $bit){
if(strlen($bit) > 0 && $bit[0] === '#') $newquery[] = $bit;
}
$newquery = implode('', $newquery);
$keywords = explode(" ", preg_replace("/\s+/", " ", $newquery));
foreach($keywords as $keyword){
$wherelike[] = "tags LIKE '%".ltrim($keyword,'#')."%'";
}
$tags = implode(" or ", $wherelike);
return $tags;
}
Возвращается (поиск # mat # godis)
select * from stores where name LIKE '%%' and name LIKE '%#godis%' and tags LIKE '%mat#godis%'order by id desc limit 8
Я хочу, чтобы запрос был примерно таким
select * from stores where name LIKE '%%'and tags LIKE '%mat%' and tags LIKE '%godis%' order by id desc limit 8
Этот дизайн действительно плох. Вам нужно использовать таблицу отношений. Проблема в том, если вы пытаетесь найти %#mat%
то есть, если есть тег #matheus
, это также даст вам результат.
Конечно, есть обходной путь для этой ситуации, но это слишком сложно.
И я не понимаю, что это: name LIKE '%%'
Так что вам нужно, чтобы создать таблицу, как упоминалось ChrisForrence, под названием store_tag
как это:
CREATE TABLE IF NOT EXISTS `store_tag` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tag` varchar(255) NOT NULL COMMENT 'Tag like #mat',
`user_id` int(11) NOT NULL COMMENT 'The foreign ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
После этого вам нужно написать небольшой скрипт, который будет цикличным по всем записям в вашей исходной таблице, получить идентификатор и теги, разобрать теги, вставить его отдельно в новую таблицу. store_tag
,
А затем используйте:
SELECT * FROM store_tag, orig_table INNER JOIN origTable ON origTable.id = store_tag.user_id WHERE tag = '#mat' OR tag = '#godis'
(Запрос выше не проверен, это только для примера, и, конечно, вам не нужно SELECT *
).
Это вернет вам желаемые результаты.
Намного легче поддерживать ваши данные.
Конечно, перед этим создайте резервную копию из вашей существующей базы данных.
Как я уже упоминал в своем комментарии, я бы создал отдельную таблицу для тегов, например:
# The original table. Notice the lack of a 'tags' column
CREATE TABLE `stores` (
`id` INTEGER UNSIGNED AUTO_INCREMENT,
`name` VARCHAR(64) UNIQUE,
PRIMARY KEY(`id`)
);
# A new table, relating stores to tags
CREATE TABLE `store_tags` (
`store_id` INTEGER UNSIGNED,
`label` VARCHAR(64),
PRIMARY KEY(`store_id`, `label`),
FOREIGN KEY(`store_id`) REFERENCES `stores`(`id`) ON DELETE CASCADE
);
Отсюда вы можете использовать вариант следующего запроса, чтобы проверить магазины, соответствующие всем тегам:
SELECT * FROM `stores`
WHERE `id` IN (SELECT `store_id` FROM `store_tags` WHERE `label`='mat')
AND `id` IN (SELECT `store_id` FROM `store_tags` WHERE `label`='godis')
ORDER BY `id` DESC LIMIT 8
Вы можете использовать это, чтобы разделить теги в правильное предложение WHERE вместе с массивом тегов, используемых в качестве входных параметров для вашего запроса PDO
/* Returns an array containing the WHERE clauses, along
* with the tags themselves (used to populate the input parameters for PDO)
*/
function searchTags($in) {
$rQ = '';
// Filter out empty array input elements
$tags = array_filter(explode('#', $in));
if(!count($tags)) {
return false;
}
$first = true;
foreach($tags as $tag) {
$rQ .= ($first ? ' WHERE' : ' AND') . ' `id` IN (SELECT `store_id` FROM `store_tags` WHERE `label`=?)';
if($first) $first = false;
}
return array($rQ, $tags);
}