简体   繁体   English

在此查询中添加多对多表关系

[英]adding a many-to-many table relationship into this query

I have what (with my limited MYSQL knowledge) is a relatively complex query: 我有(相对于我有限的MYSQL知识)是一个相对复杂的查询:

    $sQuery = "
        SELECT SQL_CALC_FOUND_ROWS
    songsID, song_name, artist_band_name, author, song_artwork, song_file,
    song_description, uploaded_time, emotion, tempo,
    user, happiness, instruments, similar_artists, play_count,
    projects_count,
    rating, ratings_count, waveform, datasize, display_name, user_url,
    IF(user_ratings_count, 'User Voted', 'Not Voted') as voted 
FROM (
        SELECT
            sp.songsID, projects_count,
            AVG(rating) as rating,
            COUNT(rating) AS ratings_count,
            COUNT(IF(userid=$userid, 1, NULL)) as user_ratings_count

                FROM (
                    SELECT songsID, COUNT(*) as projects_count
                    FROM $sTable s
                    LEFT JOIN $sTable2 p ON s.songsID = p.songs_id

                    GROUP BY songsID) as sp

            LEFT JOIN $sTable3 r ON sp.songsID = r.songid

            GROUP BY sp.songsID) as spr


JOIN $sTable s USING (songsID)
LEFT JOIN $sTable5 q ON s.user = q.ID   


        $sWhere
        $sOrder
        $sLimit

This query gets all the information about a given song from 5 different tables. 该查询从5个不同的表中获取有关给定歌曲的所有信息。

the variable $sWhere builds the WHERE part of the query and depends on the data sent to the server in order for this list of songs to be dynamically filterable based on the user input. 变量$ sWhere用于构建查询的WHERE部分,并取决于发送到服务器的数据,以便可以根据用户输入动态过滤此歌曲列表。

$sOrder and $sLimit order and limit the results again based on user input. $ sOrder和$ sLimit排序并根据用户输入再次限制结果。

I now need to add a 6th table in to this equation which contains a list of genre's (wp_genres), this table is linked to the songsID column in $sTable via a link table (wp_song_genres) with the following structure:- 我现在需要在此方程式中添加一个第六表,其中包含一个流派(wp_genres)列表,该表通过链接表(wp_song_genres)通过以下结构链接到$ sTable中的songsID列:-

$sTable(wp_songs)    $sTable6(wp_genre_songs)     $sTable7(wp_genres)
songsID*             song_id*                     genre_id**
column2              genre_id**                   genre_name
column3                                           icon_url
column4
column5
etc...

The asterisks denote the links. 星号表示链接。

What I need to do is to allow my dynamic filter of the song results to be able to filter the list of songs by Genre but I can't work out how to introduce the new table(s) ($sTable6 and $sTable7) into the query. 我需要做的是允许对歌曲结果进行动态过滤,从而能够按流派过滤歌曲列表,但我无法弄清楚如何将新表($ sTable6和$ sTable7)引入查询。

Below is the code generating the WHERE part of my query: 以下是生成查询的WHERE部分的代码:

This part takes the text recieved via 'sSearch' and searches the columns for any matching text. 这部分采用通过“ sSearch”接收的文本,并在各列中搜索任何匹配的文本。

    $sWhere = "";
if ( $_GET['sSearch'] != "" )
{
    $aWords = preg_split('/\s+/', $_GET['sSearch']);
    $sWhere = "WHERE (";

    for ( $j=0 ; $j<count($aWords) ; $j++ )
    {
        if ( $aWords[$j] != "" )
        {
            $sWhere .= "(";
            for ( $i=0 ; $i<count($aColumns) ; $i++ )
            {
                $sWhere .= $aColumns[$i]." LIKE '%".mysql_real_escape_string( $aWords[$j] )."%' OR ";
            }
            $sWhere = substr_replace( $sWhere, "", -3 );
            $sWhere .= ") AND ";
        }
    }
    $sWhere = substr_replace( $sWhere, "", -4 );
    $sWhere .= ')';
}

This part is a 'range' filter so that the user can input a minimum tempo value and a maximum tempo value (done via a jquery range slider on the font end). 这部分是一个“范围”过滤器,以便用户可以输入最小速度值和最大速度值(通过字体末端的jquery范围滑块完成)。 The data is recieved via sSearch_*. 数据通过sSearch_ *接收。

/* Individual column filtering */
for ( $i=0 ; $i<count($aColumns) ; $i++ )
{
    if ( $_GET['bSearchable_'.$i] == "true" && $_GET['sSearch_'.$i] != '' )
    {
        if ( $sWhere == "" )
        {
            $sWhere = "WHERE ";
        }
        else
        {
            $sWhere .= " AND ";
        }







        $columnFilterValue = mysql_real_escape_string($_GET['sSearch_' . $i]);
        // check for values range
        $rangeSeparator = "~";
        if (!empty($rangeSeparator) && strstr($columnFilterValue, $rangeSeparator)) {
            // get min and max

             $columnFilterRangeMatches =  explode('~', $columnFilterValue);

            // get filter
            if (empty($columnFilterRangeMatches[0]) && empty($columnFilterRangeMatches[1]))
                $sWhere .= " 0 = 0 ";
            else if (!empty($columnFilterRangeMatches[0]) && !empty($columnFilterRangeMatches[1]))
                $sWhere .= $aColumns[$i] . " BETWEEN '" . $columnFilterRangeMatches[0] . "' and '" . $columnFilterRangeMatches[1] . "' ";
            else if (empty($columnFilterRangeMatches[0]) && !empty($columnFilterRangeMatches[1]))
                $sWhere .= $aColumns[$i] . " < '" . $columnFilterRangeMatches[1] . "' ";
            else if (!empty($columnFilterRangeMatches[0]) && empty($columnFilterRangeMatches[1]))
                $sWhere .= $aColumns[$i] . " > '" . $columnFilterRangeMatches[0] . "' ";
        } else {
            $sWhere .= $aColumns[$i] . " LIKE '%" . $columnFilterValue . "%' ";
        }
    }
}

The data for the genre_id's will be coming in via sSearch_23. genre_id的数据将通过sSearch_23输入。 ie $_GET['sSearch'] will contain the genre_id I wish to filter the results by. 即$ _GET ['sSearch']将包含我希望用来过滤结果的genre_id。 Please note that I need to be able to add the results of many genre tags together. 请注意,我需要能够将许多类型标签的结果加在一起。

If a user chooses genre:rock (genre_id: 1) then all songs in $sTable that have a genre_id:1 associated with them should be returned. 如果用户选择genre:rock(genre_id:1),则应返回$ sTable中所有与genre_id:1相关联的歌曲。 (along with the rest of the information about the songs as retrievedby my current query. (以及我当前查询检索到的有关歌曲的其余信息。

But... If the user selects genre:rock (genre_id:1) AND genre:pop (genre_id:2) AND genenre:rap (genre_id:3) then all songs with ANY of those tags should be returned. 但是...如果用户选择genre:rock(genre_id:1)AND genre:pop(genre_id:2)AND genenre:rap(genre_id:3),则应返回所有带有这些标签中任何一个的歌曲。

My apologies that this is such a complex question and I realise I may not have articulated it well. 我很抱歉这是一个非常复杂的问题,我意识到我可能没有很好地阐明它。 Also I understand that this is all quite specific to my current code. 我也知道这都是我当前代码所特有的。 Regardless I really hope someone can help me or at least pint me in the right direction. 无论如何,我真的希望有人能帮助我或至少朝正确的方向努力。

Many thanks! 非常感谢!

EDIT: 编辑:

I have just anaged to get his to 'nearly' work by adding the folling into my query: 我只是想通过将以下代码添加到我的查询中来使他“接近”工作:

LEFT JOIN (
            SELECT igs.song_id, igs.genre_id, g.genre_name
            FROM $sTable6 AS igs
            JOIN wp_genres AS g 
            ON igs.genre_id = g.genre_id
            ) as gs 
            ON songsID = gs.song_id         

So that the whole thing now looks like:- 这样整个事情看起来像:

    $sQuery = "
        SELECT SQL_CALC_FOUND_ROWS
    songsID, song_name, artist_band_name, author, song_artwork, song_file,
    genre, song_description, uploaded_time, emotion, tempo,
    user, happiness, instruments, similar_artists, play_count,
    projects_count,
    rating, ratings_count, waveform, datasize, display_name, user_url, genre_id,
    IF(user_ratings_count, 'User Voted', 'Not Voted') as voted 
FROM (
        SELECT  
            sp.songsID, projects_count, 
            AVG(rating) as rating,
            COUNT(rating) AS ratings_count,
            COUNT(IF(userid=$userid, 1, NULL)) as user_ratings_count

                FROM (
                    SELECT songsID, COUNT(*) as projects_count
                    FROM $sTable s
                    LEFT JOIN $sTable2 p ON s.songsID = p.songs_id

                    GROUP BY songsID) as sp

            LEFT JOIN $sTable3 r ON sp.songsID = r.songid





            GROUP BY sp.songsID) as spr

LEFT JOIN (
            SELECT igs.song_id, igs.genre_id, g.genre_name
            FROM $sTable6 AS igs
            JOIN wp_genres AS g 
            ON igs.genre_id = g.genre_id
            ) as gs 
            ON songsID = gs.song_id         



JOIN $sTable s USING (songsID)
LEFT JOIN $sTable5 q ON s.user = q.ID   





        $sWhere
        $sOrder
        $sLimit

The queries by genre_id now happen perfectly and dynamically as intended. genre_id的查询现在可以按预期的方式完美动态地进行。 However I am getting dupilcate rows when no genre_id is specified in the WHERE part of the query. 但是,当在查询的WHERE部分中未指定genre_id时,我得到了dupilcate行。 Each song that has an entry in the songs/genres link table gets duplicated. 在歌曲/流派链接表中具有条目的每首歌曲都会被复制。

First of all is my current solution a good one in terms of optimization/best practices? 首先,就优化/最佳实践而言,我当前的解决方案是一个好的解决方案吗? Secondly, how can I prevent these duplicate rows? 其次,如何防止这些重复的行?

NOTE: I do already have a unique primary key across both columns in the link table. 注意:我已经在链接表的两列中都有唯一的主键。

http://hackmysql.com/case4 I think this would serve as a good read for you, especially considering your database may reach huge amounts of rows. http://hackmysql.com/case4我认为这对您是一个很好的阅读,特别是考虑到您的数据库可能会到达大量的行。 Using index keys in your mysql table can greatly speed up queries where one table must draw from another table or where one table has many rows which may have similar values in one column but not others. 在您的mysql表中使用索引键可以极大地加快查询,其中一个表必须从另一表中绘制,或者一个表中有许多行,其中一列可能具有相似的值,而其他列则没有。 This keeps them from having to scan the whole table, at least to my knowledge. 至少就我所知,这使他们不必扫描整个表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM