联合多关系 MySQL 数据库中的高级搜索

发布于 2024-10-03 09:02:51 字数 2173 浏览 4 评论 0原文

这可能解释起来有点高级,因为这是我想做的一件相当复杂的事情(至少对我来说)。

我目前正在用 PHP 和 MySQL 构建一个供个人使用的电影数据库,而 MySQL 部分让我很烦恼。当前的设置是这样的:

我有一个主电影数据库,其中包含名称、描述和值以及单个选项(例如年份、年龄限制和媒体类型(DVD、蓝光等))。

我还有额外的语言表、字幕、音频格式等,它们都有两列,一列用于匹配索引(例如语言 ID)。 理想

我的语言表的示例:

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 字段中返回搜索到的数字/id。

然后我使用 IN() 函数修复了它。至少我认为我做到了。但问题是这只适用于我所说的 OR 搜索。添加:

WHERE movie_subtitles.subid IN ()

对于不在字幕表中的数字,仍将返回该行,只是仅包含匹配的数字。这对于一半的搜索来说很好,但我还需要一种使用类似 AND 的方法进行搜索的方法。

我不知道我是否需要完全重组,或者需要完全不同的查询,但我希望得到一些帮助或提示。

也许我应该说我也看过 HAVING 选项,但据我所知,它对我的​​查询不起作用。

顺便说一句,如果这是不可能做到的,我考虑过废弃连接的表,并将它们替换为主电影表中易于搜索的字段(例如使用此“语法”:'#2##4#',然后使用 LIKE '%#2#%' AND '%#4#%' 来匹配结果,或者作为最后的手段使用 PHP 来排序(我宁愿死也不愿这样做),尽管我宁愿喜欢它如果上述解决方案可以修复并使用)。

预先非常感谢您帮助我解决头痛问题!

This might be a bit advanced to explain, as it's a pretty complicated thing I'm trying to do (at least to me).

I'm currently building a movie-database for personal use in PHP and MySQL, and the MySQL part is killing me. The current setup is like this:

I have a main movie database containing names, description and values with a single option (like year, age-limit and media-type (DVD, Blu-Ray, etc).

I have additional tables for language, subtitles, audio-formats etc. which all have two columns. One for the ID of the movie, and one that matches an index (eg. language id). These are supposed to be joined together with the main table, and concatted into a single field.

Example of my language table:

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

Optimally, I would like something like this:

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

With the subtitles and languages being able to be exploded to a PHP array. That part I've actually got working just fine using GROUP_CONCAT, right up 'till the part where I need to search for specific subid's or langid's. This is the query I've been using so far. I hope you'll get the idea even though I havent written out all my table info:

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

I use the group_concat_max_len to prevent me getting a BLOB, and so far I have only tried group_concatting two of my joined tables (will add the rest later).

This returns exactly what I want, but I can only have one WHERE clause per joined table or it'll return 0 rows. Again, if I only search for one, it will only return the searched number/id in the GROUP_CONCAT'ted field.

Then I sorta fixed it using the IN() function. At least I thought I did. But the problem is that only works with what I'd call OR-searches. Adding:

WHERE movie_subtitles.subid IN ()

With numbers not in the subtitles table will still return the row, just only with the matching numbers. This is fine for half the searches, but I need a way to search with the AND-like method as well.

I have no idea if I need to restructure completely, or need a totally different query, but I hope for some assistance or hints.

I should perhaps say that I've had a look at the HAVING option as well, but as far as I've understood, it will not be effective on my query.

By the way, if this is impossible to do, I've considered scrapping the joined tables and replacing them with a field easily searchable in the main movie table (like using this "syntax": '#2##4#' and then using LIKE '%#2#%' AND '%#4#%' to match results, or as a last resort using PHP to sort it out (I'd rather die than doing that), though I'd rather like it if above solution could be fixed and used).

Thanks a lot in advance for helping away my headaches!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

柠檬 2024-10-10 09:02:51

对您的选择进行子查询,然后您将可以更轻松地使用子句。

就像:

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

嗯,它并不完美,因为你的 id 将被转换成字符串(在 postgres 中你有数组,所以你可以从顶层进行适当的搜索。)我不认为我真的想用正则表达式搜索 id尽管。

那么最好不要在最终关卡之前连接您的 id。所以你想要 3 级查询:

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

) as outer

编辑

试试这个:

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

Sub-query your select then you will have an easier time with your clauses.

Like:

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

Well, its not perfect since your ids will have been turned into strings (In postgres you have arrays so you could do a proper search from the top level.) I don't think I would really want search for ids with regular expressions though.

It would be better then, to not concatenate your ids until the final level. So you want 3 levels of queries:

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

) as outer

edit

try this:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文