【问题标题】:Normalised database - ONE to MANY - Search through all joined data sets标准化数据库 - 一对多 - 搜索所有连接的数据集
【发布时间】:2012-03-24 10:10:02
【问题描述】:

我正在尝试构建一个 MySQL 查询,该查询将允许我在数据库中提取具有流行和电子流派的曲目的歌曲标题。

+----------------------------------------------------+
TABLE: SONG
+----------------------------------------------------+
song_id  | title       |  
1        | song name   | 


+----------------------------------------------------+
TABLE: GENRE
+----------------------------------------------------+
genre_id   | name       | 
1          | Pop        |    
2          | Electronic |   


+----------------------------------------------------+
TABLE: SONG_GENRE
+----------------------------------------------------+
genre_id  | song_id | 
1         | 1       | 
2         | 1       | 

这个 SQL 不起作用,因为它显然永远不会返回 1 和 2 的genre_id,但这是我卡住的地方。

SELECT DISTINCT song.song_id, song.title
                    FROM song
                    LEFT JOIN song_genre ON song_genre.song_id = song.song_id
                    LEFT JOIN genre ON genre.genre_id = song_genre.genre_id
                    WHERE genre.genre_id ='1'
                    AND genre.genre_id='2'

如果有人能指出我正确的方向,我会非常感激!

【问题讨论】:

    标签: mysql sql relational-database normalization


    【解决方案1】:
                    WHERE genre.genre_id ='1'
                    AND genre.genre_id='2'
    

    您的查询正确吗?

    如果,那么这意味着在这两种情况下都必须为真,但每行只有一个genre_id! 也许用“OR”或...genre.genre_id IN (1,2)

    【讨论】:

      【解决方案2】:

      假设数据已标准化,并且与您的样本中的字符一样:

      SELECT
         song.song_id, 
         song.title
      FROM 
         song
            INNER JOIN song_genre ON song_genre.song_id = song.song_id
            INNER JOIN genre ON genre.genre_id= song_genre.genre_id
      WHERE 
         genre.genre_id in ('1', '2')
      

      根据您的评论修改:

      SELECT
         song.song_id, 
         song.title
      FROM 
         song
            INNER JOIN song_genre ON song_genre.song_id = song.song_id
            INNER JOIN genre g1 ON g1.genre_id = song_genre.genre_id
            INNER JOIN genre g2 ON g2.genre_id = song_genre.genre_id
      WHERE 
         g1.genre_id = '1' and
         g2.genre_id = '2'
      

      【讨论】:

      • 这将返回所有类型为流行或电子的结果。如果我只想要同时具有流行和电子流派的结果怎么办?
      【解决方案3】:

      这是一种方法:

          SELECT DISTINCT song.song_id, song.title
          FROM song
          INNER JOIN (SELECT songid FROM song_genre WHERE song_genre.genre_id ='1') genre1 
               ON genre1.song_id = song.song_id
          INNER JOIN (SELECT songid FROM song_genre WHERE song_genre.genre_id ='2') genre2 
               ON genre2.song_id = song.song_id
      

      另一种可能更有效的方法。这假设在 song_genre 中没有重复。 COUNT(*) = X,其中 X 等于列出的流派数。

      SELECT DISTINCT song.song_id, song.title
      FROM song
      INNER JOIN (SELECT songid, COUNT(*) FROM song_genre 
      WHERE genre_id IN ('1','2') 
      GROUP BY songid HAVING COUNT(*) = 2) genre1 ON genre1.song_id = song.song_id
      

      【讨论】:

      • 感谢您的帮助。这确实有效,但我不确定这将如何扩展。例如,如果我添加了乐器、心情等,它将创建一个相当大的查询。这会有多高效?我的数据库设计有问题吗?如果有,我该如何改进它?
      • 更新了更易于管理的 sql 的答案。你的设计很好 - 我一直认为正确规范化是要走的路。就表演而言,我不会太担心。如果以后遇到问题,可以考虑去规范化。
      • 这是一个很好的答案,我已经成功地做到了我所需要的。感谢您的帮助。
      猜你喜欢
      • 2015-06-27
      • 2013-07-21
      • 1970-01-01
      • 2019-10-22
      • 1970-01-01
      • 1970-01-01
      • 2017-05-16
      • 1970-01-01
      • 2020-04-19
      相关资源
      最近更新 更多