Расширенный поиск в объединенной многоуровневой базе данных MySQL - PullRequest
0 голосов
/ 21 ноября 2010

Это может быть немного сложнее для объяснения, так как это довольно сложная вещь, которую я пытаюсь сделать (по крайней мере, для меня).

В настоящее время я создаю базу данных фильмов для личного использования в PHP и MySQL, и часть MySQL убивает меня. Текущая настройка выглядит следующим образом:

У меня есть основная база данных фильмов, содержащая имена, описания и значения с одним параметром (например, год, возраст и тип носителя (DVD, Blu-Ray и т. Д.).

У меня есть дополнительные таблицы для языка, субтитров, аудио-форматов и т. Д., Которые все имеют два столбца. Один для идентификатора фильма, а другой соответствует индексу (например, идентификатору языка). Предполагается, что они будут объединены с основной таблицей и объединены в одно поле.

Пример моей языковой таблицы:

movid | langid
--------------
1     | 2
1     | 4
2     | 4
3     | 5     

Оптимально, я бы хотел что-то вроде этого:

| ID | name    | description | year | subtitles | languages | audio |
--------------------------------------------------------------------
| 1  | One     | Bla bla     | 2010 | 2,3,5,6,7 | 3,6,22,6  | 10,5  |
| 2  | Another | foo bar     | 2008 | 6,33,5,27 | 10,4,2,3  | 8,15  |

С субтитрами и языками, которые могут быть преобразованы в массив PHP. Эта часть у меня на самом деле отлично работает, используя GROUP_CONCAT, вплоть до той части, где мне нужно искать конкретные subid или langid. Это вопрос, который я использовал до сих пор. Я надеюсь, что вы поймете идею, хотя я не выписал всю информацию о моей таблице:

SET SESSION group_concat_max_len = 512;

SELECT
movie.id,
movie.name,
movie.origname,
movie.`year`,
movie.`type`,
movie.duration,
movie.age,
GROUP_CONCAT(DISTINCT movie_language.langid ORDER BY langid) AS lang,
GROUP_CONCAT(DISTINCT movie_subtitles.subid ORDER BY subid) AS subtitles

FROM `movie`

LEFT JOIN `movie_audio` ON `movie`.`id`=`movie_audio`.`movid` 
LEFT JOIN `movie_company` ON `movie`.`id`=`movie_company`.`movid` 
LEFT JOIN `movie_genre` ON `movie`.`id`=`movie_genre`.`movid` 
LEFT JOIN `movie_language` ON `movie`.`id`=`movie_language`.`movid` 
LEFT JOIN `movie_subtitles` ON `movie`.`id`=`movie_subtitles`.`movid` 

GROUP BY movie.id

Я использую group_concat_max_len, чтобы помешать мне получить BLOB, и до сих пор я пробовал group_concatting только две из моих объединенных таблиц (остальные добавлю позже).

Это возвращает именно то, что я хочу, но у меня может быть только одно предложение WHERE для объединенной таблицы, иначе будет возвращено 0 строк. Опять же, если я только ищу один, он вернет только искомый номер / идентификатор в поле GROUP_CONCAT'ted.

Затем я исправил это, используя функцию IN (). По крайней мере, я так и думал. Но проблема в том, что это работает только с тем, что я бы назвал OR-поиском. Добавление:

WHERE movie_subtitles.subid IN ()

Если числа не указаны в таблице субтитров, строка все равно будет возвращаться, только с соответствующими номерами. Это нормально для половины запросов, но мне также нужен способ поиска с использованием метода, подобного AND.

Я понятия не имею, нужно ли мне полностью реструктурировать или нужен совершенно другой запрос, но я надеюсь на некоторую помощь или подсказки.

Возможно, мне следует сказать, что я также рассмотрел опцию HAVING, но, насколько я понял, она не будет эффективной в моем запросе.

Кстати, если это невозможно, я рассмотрел вопрос об удалении объединенных таблиц и замене их полем, легко доступным для поиска в основной таблице фильмов (например, используя этот «синтаксис»: '# 2 ## 4 # 'и затем использовать LIKE'% # 2 #% 'AND'% # 4 #% 'для сопоставления результатов или в качестве крайней меры, используя PHP для сортировки (я лучше умру, чем сделаю это), хотя я бы скорее нравится, если вышеуказанное решение можно исправить и использовать).

Заранее большое спасибо за помощь в устранении моих головных болей!

1 Ответ

0 голосов
/ 21 ноября 2010

Подзапросите ваш выбор, тогда вам будет легче с вашими предложениями.

Как:

select *
   from (`your big query above`) as t
where subtitles regexp `your ids you want`
and lang regexp `your ids you want`

Ну, это не идеально, так как ваши идентификаторы будут превращены в строки(В postgres у вас есть массивы, чтобы вы могли правильно выполнить поиск с верхнего уровня.) Я не думаю, что я действительно хотел бы искать идентификаторы с регулярными выражениями.

Тогда было бы лучше, если бы необъединить ваши идентификаторы до последнего уровня.Итак, вам нужно 3 уровня запросов:

select 
  stuff, ...
  group_concats
from
(
    select *
       from (`your big query above but without the group_concat`) as inner
    conditions ...

) as outer

edit

Попробуйте это:

SELECT
id,
name,
origname,
`year`,
`type`,
duration,
age,

-- at this point we have the right rows we are just
-- grouping lang and subtitles
GROUP_CONCAT(DISTINCT langid ORDER BY langid) AS lang,
GROUP_CONCAT(DISTINCT subid ORDER BY subid) AS subtitles

from
(

    (
        SELECT
            movie.id,
            movie.name,
            movie.origname,
            movie.`year`,
            movie.`type`,
            movie.duration,
            movie.age,
            langid,
            subid


            FROM `movie`

            LEFT JOIN `movie_audio` ON `movie`.`id`=`movie_audio`.`movid`
            LEFT JOIN `movie_company` ON `movie`.`id`=`movie_company`.`movid`
            LEFT JOIN `movie_genre` ON `movie`.`id`=`movie_genre`.`movid`
            LEFT JOIN `movie_language` ON `movie`.`id`=`movie_language`.`movid`
            LEFT JOIN `movie_subtitles` ON `movie`.`id`=`movie_subtitles`.`movid`


            -- each row will have a different langid and different subid
            GROUP BY
                movie.id, langid, subid

    ) as inner

    -- you should be able to do any complex condition as this point
    where
        (langid = 1 or langid = 2)
        and (subid = 2 or subid = 3)

) as outer
...