2016-10-26 3 views
0

В настоящее время я разрабатываю веб-сайт для файлового хостинга. Я сортирую файлы по тегам, и у меня есть проблема для создания запроса на поиск в SQL. Если я ищу несколько тегов сразу, я хочу получить файлы, которые имеют все эти теги.SQL-запросы с краткими тегами

Ниже приведен пример того, что я хочу сделать. Если мой поиск «#code #python», мой запрос должен вернуть мне файлы с обоими тегами (файл с id 2 в этом примере). Если поиск просто «# код», запрос должен возвращать файлы 2 и 3.

Вот как я храню все данные, у меня есть таблица для файлов, одна для тегов и другая с ссылками между файлы и теги (files_tags).

Table Tags 
------------------------ 
| id | name   | 
------------------------ 
| 1 | Code   | 
------------------------ 
| 2 | Python   | 
------------------------ 
| 3 | PHP    | 
------------------------ 

Table Files 
------------------------ 
| id | name   | 
------------------------ 
| 1 | python.pdf  | (#python) 
------------------------ 
| 2 | main.py   | (#code #python) 
------------------------ 
| 3 | class.php  | (#code #php) 
------------------------ 

Table files_tags 
------------------------ 
| id | tag | file  | 
------------------------ 
| 1 | 1 | 2   | 
------------------------ 
| 2 | 1 | 3   | 
------------------------ 
| 3 | 2 | 1   | 
------------------------ 
| 4 | 2 | 2   | 
------------------------ 
| 5 | 3 | 3   | 
------------------------ 

Мой текущий запрос:

SELECT DISTINCT `files`.* FROM `files`, `files_tags`, `tags` WHERE `files`.`id` = `files_tags`.`file` AND `files_tags`.`tags` = `tags`.`id` AND `tags`.`name` LIKE %"#code #python"%; 

Но это заставляет меня все 3 файла, а не просто подать 2.

Что я делаю неправильно?

Спасибо за помощь

ответ

0

Спасибо, это работает.

select * from files where 2 = (select count(1) from tags inner join files_tags on files_tags.tag = tags.id where files_tags.file = files.id and tags.name in ("code","python")) 
+0

Я думаю, вам нужно 'where 2 <= ...' получить все файлы, имеющие хотя бы те теги 2 – apokryfos

0

Ваш синтаксис выглядит странно. Попробуйте следующее одно вместо:

SELECT `files`.`id`, `files`.`name` 
FROM `files` 
     JOIN `files_tags` ON `files`.`id`=`files_tags`.`file` 
     JOIN `tags` ON `files_tags`.`tag` = `tags`.`id` 
WHERE `tags`.`name` IN ('code','python'); 
GROUP BY `files`.`id`, `files`.`name` 
+0

предложение IN является OR, поэтому я получаю все 3 файла, потому что каждый из них соответствует тегам. – BadTigrou

0

Я бы рекомендовал что-то вроде этого:

SELECT f.* 
FROM `files` f JOIN 
    `files_tags` ft 
    ON f.id = ft.file JOIN 
    `tags` t 
    ON ft.tags = t.id 
WHERE FIND_IN_STR(t.name, @SearchStr) 
GROUP BY f.id 
HAVING COUNT(*) = LENGTH(@SearchStr) - LENGTH(REPLACE(@SearchStr, ',', '')) + 1; 

Это берет на себя смелость изменить формат вашей строки поиска. Вместо «#» просто используйте запятые (без пробелов). Конечно, вышеупомянутое может быть адаптировано для поддержки «#», но для этого кода требуется больше манипуляций с строкой.

0

Прежде всего, вы можете взять текст поиска и использовать его как массив, то есть не строку. Разделить значения по пространству «", поэтому у вас есть массив, в котором каждый элемент представляет собой тег.

выберите * из файлов, где length_of_tags_array = (выберите кол (1) от метки внутреннего соединения files_tags на files_tags.tag = tags.id где files_tags.file = files.id и tags.name в ("+ putyourtagshere +") )

  • так как ваши метки являются строками, добавить каждый элемент enbetween quitations
  • не использовать, как в этом случае для него будет извлекать метки, которые подстрока POF других тегов, такие как «C» подстрока " C# "
  • удалить хэштег, так как он i s не в названии вашего сохраненного тега