MySQL LEFT JOIN显示问题需要帮助

时间:2011-08-13 20:44:20

标签: php mysql logic

我正在尝试在网页上正确显示MySQL查询。

我有4个连接在一起的简单表格

singerssinger_idsinger_name

songssinger_idsong_namealbum_id

albumssinger_idalbum_idalbum_name

我已经设法使用此查询获取这些表。

SELECT singers.singer_name, songs.song_name, albums.album_name

FROM singers 
LEFT JOIN songs ON singers.singer_id = songs.singer_id
LEFT JOIN albums ON albums.album_id = songs.album_id
WHERE singers.singer_id = ?
ORDER BY songs.song_id DESC

我现在遇到的问题是我似乎无法正确显示这些表格。

假设我有一个拥有1张专辑和11首歌曲的歌手。 这是我为这位歌手所得到的结果。

singer_name  |     song_name     |     album_name
__________________________________________________

singer name  |  song name        |    album name
singer name  |  song name        |    album name
singer name  |  song name        |    album name
singer name  |  song name        |    album name
singer name  |  song name        |    album name
singer name  |  song name        |    album name
singer name  |  song name        |    album name
singer name  |  song name        |    album name
singer name  |  song name        |    album name
singer name  |  song name        |    album name
singer name  |  song name        |    album name

所以我没有获得1张专辑,而是获得了11次相同的专辑。

网页上的

我正在使用foreach()显示相册 而且我得到的是同一张专辑而不是一张专辑。

现在提出问题......

如何才能展示专辑3次?

(没有硬编码,因为我可能还有一个有9张专辑的歌手)。

提前感谢您的帮助。

编辑:

这是我显示歌曲的方式

                        <?php foreach($results as $song): ?>
                        <tr>
                            <td></td>
                            <td>
                                <a href="/song/<?php echo urlencode($song['song_url']); ?>/" class="song">
                                    <span><?php echo $song['song_name']; ?></span>
                                </a>
                            </td>
                            <td>
                                <a href="/album/<?php echo urlencode($song['album_name']); ?>/" class="album">
                                    <?php echo $song['album_name']; ?>
                                </a>
                            </td>
                            <td>
                                <span class="time">
                                    <?php echo $song['song_time']; ?>
                                </span>
                            </td>
                            <td>
                                <a href="/search/?search=<?php echo urlencode($song['song_genre']); ?>" class="genre">
                                    <?php echo $song['song_genre']; ?>
                                </a>
                            </td>
                            <td><a href="#" class="play">נגן</a></td>
                        </tr>
                    <?php endforeach; ?>
即使歌曲没有附加到任何专辑,我也能收到所有歌曲。正是我想要的。

显示相册的问题:

                    <?php foreach($results as $album): ?>
                    <li>
                        <a href="/album/<?php echo urlencode($album['url']); ?>/" class="album">
                            <img src="/media/<?php echo $album['singer_dir'] . '/' . $album['album_thumb']; ?>" alt="" />
                            <span class="album_name"><?php echo $album['album_name']; ?></span>
                        </a>
                    </li>
                <?php endforeach; ?>
这位歌手有1张专辑,但我得了11张。因为这张专辑有11首歌曲。 我只需要显示一次......

3 个答案:

答案 0 :(得分:2)

在不了解$ result变量的情况下(例如,它可能是PDO对象或数组,我不知道)我的回答必须是一个hackish:

<?php foreach($results as $album): ?>
    <li>
        <a href="/album/<?php echo urlencode($album['url']); ?>/" class="album">
            <img src="/media/<?php echo $album['singer_dir'] . '/' . $album['album_thumb']; ?>" alt="" />
            <span class="album_name"><?php echo $album['album_name']; ?></span>
        </a>
    </li>
    <?php break; ?>
<?php endforeach; ?>

就我个人而言,我不会在我自己的代码中这样做,但如果没有更多的代码图片和更清楚地了解你想要做什么,那就是它。


编辑1:

如果是这种情况,那么您需要的只是以下内容。 foreach是不必要的:

<li>
    <a href="/album/<?php echo urlencode($result[0]['url']); ?>/" class="album">
        <img src="/media/<?php echo $result[0]['singer_dir'] . '/' . $result[0]['album_thumb']; ?>" alt="" />
        <span class="album_name"><?php echo $result[0]['album_name']; ?></span>
    </a>
</li>

编辑2:

SELECT album_name
FROM albums 
WHERE singer_id = ?

使用foreach循环遍历此结果集。

答案 1 :(得分:1)

LEFT OUTER JOIN方法按照您的设计设计,相册应该由于笛卡尔积而重复。

不清楚你的观点,我用两种方式解释你的问题。 重复歌手,重复歌曲,重复专辑,因为没有分组。 2.非重复的歌手/歌曲,只想分组专辑。

如果你的意思是1,答案很简单。添加不同的关键字 我确定你的意思是2,你应该管理重复信息。并且,如果您使用html表格输出, rowspan 属性将为您提供帮助。

示例数据:

CREATE TABLE t 
( a     varchar(25) 
, b     varchar(25) 
, c_id  integer     
, c     varchar(25) 
);

INSERT INTO t VALUES ( '2ne1', 's1', 1, 'lonely'); 
INSERT INTO t VALUES ( '2ne1', 's2', 1, 'lonely'); 
INSERT INTO t VALUES ( '2ne1', 's3', 1, 'lonely'); 
INSERT INTO t VALUES ( '2ne1', 's4', 1, 'lonely'); 
INSERT INTO t VALUES ( '2ne1', 's5', 1, 'lonely'); 

INSERT INTO t VALUES ( 'anonymous', 'rock1', 2, 'um album'); 
INSERT INTO t VALUES ( 'anonymous', 'rock2', 2, 'um album'); 
INSERT INTO t VALUES ( 'anonymous', 'rock3', 2, 'um album'); 

示例代码:

<?php

$conn = mysql_connect('localhost', '..', ',,') 
    OR die (mysql_error());
mysql_select_db('test') 
    OR die (mysql_error());
$rs = mysql_query
    ( 'select t.a, t.b, r.span, t.c_id, t.c '.
      'from t                               '.
      'join                                 '.
      '( select c_id, count(c) span         '.
      '  from t                             '.
      '  group by c_id) r                   '.
      '    on t.c_id = r.c_id               ' ) 
    OR die (mysql_error());

echo "<html><table border=1>\n";
$old_c_id = -1;
while ($row = mysql_fetch_array($rs, MYSQL_ASSOC)) {
    echo "<tr>";
    echo "<td>".htmlspecialchars($row['a'])."</td>\n";
    echo "<td>".htmlspecialchars($row['b'])."</td>\n";
    if ($old_c_id != $row['c_id'])
    {
        $old_c_id = $row['c_id'];
        echo  sprintf("<td rowspan=%d>", $row['span'])
            . htmlspecialchars($row['c'])
            . "</td>\n";
    }
    echo "</tr>\n";
}
echo "</table></html>";

?>

答案 2 :(得分:1)

请参阅我对how to display the changing values only问题的回答 - 我在previous question的评论中提到了这一点。它基本上归结为在不拆分SQL查询的情况下将结果分组到PHP中。

首先,query your database使用以下查询:

SELECT a.artist_name, COALESCE(b.album_name, '(no album)'), s.song_name, 
FROM songs s
LEFT JOIN artists a
ON s.singer_id = a.singer_id
LEFT JOIN albums b
ON s.album_id = b.album_id AND s.singer_id = b.singer_id
ORDER BY a.artist_name, b.album_id, s.song_id  # order by artist, album then song

这将为您提供一个结果集,其中每一行代表完整的歌曲(包括艺术家和专辑名称) - 想象一下电子表格 - 这就是您要求的加入到第一位。我们只输出一次这个表,打印艺术家和专辑一次(正确的ORDER BY对此非常重要。

$prev = array( 'artist' => null, 'album' => null );
while(($row = mysqli_fetch_assoc($result)) !== FALSE) {
  // print groupings
  if($row['artist_name'] != $prev['artist'])
    displayArtist(); // only display the first occurrence of each artist
  if($row['album_name'] != $prev['album'])
    displayAlbum($row['album_name']); // same goes for albums

  displaySong($row['song_name']); // but display every song

  $prev['artist'] = $row['artist_name'];
  $prev['album'] = $row['album_name'];
}

format*()可以简单如下:

function displayArtist($artist_name) {
  printf('<h1 class="artist">%s</h1>', htmlspecialchars($artist_name));
}
function displayAlbum($album_name) {
  printf('<h1 class="album">%s</h1>', htmlspecialchars($album_name));
}
function displaySong($song_name) {
  printf('<div class="song">%s</div>', htmlspecialchars($song_name));
}

但你当然可以像问题一样使用表格布局