需要 MySQL LEFT JOIN 显示问题的帮助

发布于 2024-11-29 08:17:19 字数 3933 浏览 1 评论 0原文

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

我有 4 个简单的表,将

singers 连接在一起:singer_idsinger_name

songssinger_id >, song_name, album_id

专辑 : singer_id, album_id, album_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 首歌。 我只需要显示一次......

i'm trying to display a MySQL query correctly on a web page.

i have 4 simple tables that connected together

singers: singer_id, singer_name

songs : singer_id, song_name, album_id

albums : singer_id, album_id, album_name

i already managed to get those tables using this query.

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

the problem i'm having now is that i cant seem to display those tables right.

lets say i have a singer with 1 album and 11 songs.
this is the result i'm getting for this singer.

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

so instead of getting 1 album i'm getting the same album 11 times.

on the web page i'm displaying the albums using foreach()
and i'm getting the same album instead of just one album.

now for the question....

How can i display the album ONLY 3 times?

(without hard coding because i might have a singer with 9 albums as well).

thanks in advance for any help.

EDIT:

this is how i display the songs

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

i get all the songs even if the songs are not attached to any album. just what i wanted.

the problem with displaying the albums:

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

this singer have 1 album but i get it for 11 times. i'ts because this album have 11 songs.
i need to display it only once....

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

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

发布评论

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

评论(3

翻身的咸鱼 2024-12-06 08:17:19

如果不了解 $result 变量(例如,它可能是 PDO 对象或数组,我不知道),我的答案将不得不是黑客:

<?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 循环此结果集。

Without knowing much about the $result variable (eg. it could be a PDO object or an array, I don't know) my answer will have to be a 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; ?>

Personally I wouldn't do this in my own code, but without more of a bigger picture of your code and a clearer idea of what you are trying to do, it is what it is.


Edit 1:

If that's the case then all you need is the following. The foreach is unnecessary:

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

Edit 2:

SELECT album_name
FROM albums 
WHERE singer_id = ?

And loop over this result set using the foreach.

最舍不得你 2024-12-06 08:17:19

请参阅我对问题的回答如何显示变化仅值 – 我在对您的上一篇文章的评论中提到过这一点问题。它基本上可以归结为在 PHP 中对结果进行分组,而不拆分 SQL 查询。

首先,使用以下查询查询数据库

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));
}

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

See my answer given to the question how to display the changing values only – I've mentioned that in a comment on your previous question. It basically boils down to grouping the results in PHP without splitting your SQL query.

First, query your database with the following query:

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

This will get you a result set where each row represents a full song (including artist and album name) – imagine a spreadsheet –, that's why you asked for a join in the first place. Let's output this table, printing artist and album only once (the correct ORDER BY is important for this.

$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*() can be as simple as:

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));
}

but you can of course use a table layout like in your question

内心旳酸楚 2024-12-06 08:17:19

LEFT OUTER JOIN 方法的设计如您所见,由于笛卡尔积,专辑应该重复。

你的意思不太清楚,我从两个方面解释了你的问题。
1.重复歌手、重复歌曲、重复专辑,因为没有group by。
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>";

?>

The LEFT OUTER JOIN method is designed as you seen, album should be repeated as a result of cartesian product.

It's not clear your point, I interpreted your question in two ways.
1. repeating singer, repeating songs, repeating albums, because of no group by.
2. non-repeating singer/songs, just want to grouping albums.

If you mean the way 1, the answer is simple. Add distinct keyword.
I'm sure you meant way 2, you should manage repeating information. And, if you're using html table to output, rowspan attribute will help you.

example data:

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'); 

example code:

<?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>";

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