Нужна помощь в MySQL LEFT JOIN Показать проблему - PullRequest
0 голосов
/ 14 августа 2011

Я пытаюсь правильно отобразить запрос MySQL на веб-странице.

У меня есть 4 простые таблицы, которые соединены вместе

singers: singer_id, singer_name

songs: singer_id, song_name, album_id

albums: 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 песен.мне нужно отобразить его только один раз ....

Ответы [ 3 ]

2 голосов
/ 14 августа 2011

Не зная много о переменной $ 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.

1 голос
/ 14 августа 2011

См. Мой ответ на вопрос , как отобразить только изменяющиеся значения - я упоминал об этом в комментарии к вашему предыдущему вопросу .В основном все сводится к группированию результатов в 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));
}

, ноВы, конечно, можете использовать макет таблицы, как в вашем вопросе

1 голос
/ 14 августа 2011

Метод LEFT OUTER JOIN разработан, как вы видели, альбом должен повторяться в результате декартового произведения.

Неясно, в чем ваша точка зрения, я интерпретировал ваш вопрос двумя способами.1. повторяя певца, повторяя песни, повторяя альбомы, потому что нет группы по.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>";

?>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...