0

データベースに最新のトラックを照会する mysql ステートメントがあります。ただし、データベースは部分的に正規化されているため、ID は異なるテーブルにあります。クエリでは、artists テーブルからアーティスト ID を取得し、それらを変数に入れます。変数は、トラックを調べて最新のトラックを見つけるクエリに解析されます。ここに問題があります。$artist 変数には大量の ID が含まれる可能性があるため、これらの ID はすべてクエリに解析され、クエリに LIMIT を設定したにもかかわらず、結果としていくつかの URL がまとめられます。

テーブルからすべてのアーティストを取得し、すべてのアーティストから最新のトラックを見つける必要があるため、アーティスト クエリを LIMIT できないことに注意してください。

アーティストのクエリを制限せずに、クエリから最新の URL だけを取得するにはどうすればよいですか?

//Set up artist query so only NBS artists are chose

$findartist = mysql_query("SELECT * FROM artists") or die(mysql_error());
  while ($artist = mysql_fetch_array($findartist)){

     $artist =  $artist['ID']; 

        //get track url
        $fetchurl = mysql_query("SELECT * FROM tracks WHERE id = '$artist' ORDER BY timestamp DESC LIMIT 1");

             url = mysql_fetch_array($fetchurl);
             $track_ID = $url ['ID'];
             $trackname = $url ['name'];
             $trackurl = $url ['url'];
             $artist_ID =$url['ID'];

    }

添加:

 $findartist = mysql_query("SELECT A.*, T.*
  FROM (
         SELECT T.ARTIST_ID, MIN(T.TRACK_ID) TRACK_ID
           FROM (
                    SELECT ARTIST_ID, MAX(`TIMESTAMP`) `TIMESTAMP`
                      FROM TRACKS
                  GROUP BY ARTIST_ID
                 ) L
           JOIN TRACKS T ON (    L.ARTIST_ID   = T.ARTIST_ID 
                             AND L.`TIMESTAMP` = T.`TIMESTAMP`)
       GROUP BY T.ARTIST_ID
       ) X
  JOIN ARTISTS A ON X.ARTIST_ID = A.ARTIST_ID
  JOIN TRACKS  T ON (X.TRACK_ID = T.TRACK_ID AND X.ARTIST_ID = T.ARTIST_ID)
  ORDER BY A.NAME");



             while ($artist = mysql_fetch_array($findartist)){

             $artist =  $artist['ID']; 
             $trackurl = $artist['url'];
4

3 に答える 3

1

正しく理解している場合、アーティスト テーブル内の各アーティストの最新 (最新のタイムスタンプ) トラックが必要です。

テーブル定義が表示されていると役立ちます。テーブルからのクエリで ARTIST_ID と TRACK_ID を混同していると思いますtracks。そのため、全体を通して列名 ARTIST_ID と TRACK_ID を使用します。

(ちなみに、これは MySQL のデータ型名でもあるため、列名として TIMESTAMP を選択するのは残念です。どうでもいいです。)

これは、1 つのクエリで実行できます。そのクエリを作成しましょう。とても単純ではありませんが、うまく機能します。

まず、アーティストごとに最新のトラックのタイムスタンプを取得しましょう。これにより、ARTISTS_ID と最新の TIMESTAMP が表示された仮想テーブルが返されます。

   SELECT ARTIST_ID, MAX(`TIMESTAMP`) `TIMESTAMP`
     FROM TRACKS
 GROUP BY ARTIST_ID

では、そのクエリを別のクエリにネストして、各アーティストの最新トラックである特定の track_id を見つけてみましょう。アーティストが正確に同じタイムスタンプを持つ複数のトラックを持っている状況を明確にする必要があります。この場合、最小番号の TRACK_ID を取得します。

アーティストのアルバムのすべてのトラックのタイムスタンプは同じですが、トラック ID が昇順であるため、アーティストの最新アルバムの最初のトラックが選択されます。

  SELECT T.ARTIST_ID, MIN(T.TRACK_ID) TRACK_ID
    FROM (
             SELECT ARTIST_ID, MAX(`TIMESTAMP`) `TIMESTAMP`
               FROM TRACKS
           GROUP BY ARTIST_ID
          ) L
    JOIN TRACKS T ON (    L.ARTIST_ID   = T.ARTIST_ID 
                      AND L.`TIMESTAMP` = T.`TIMESTAMP`)
GROUP BY T.ARTIST_ID

これがどうなるかわかりますか?内側のサブクエリは各アーティストの最新のタイムスタンプを見つけ、外側のクエリはサブクエリを使用して、そのアーティストとタイムスタンプの最小番号のトラック ID を見つけます。これで、各アーティストの最新の track_id を示す仮想テーブルができました。

最後に、結合されたアーティストとトラックの情報を照会して、アーティストとその最新トラックのリストを取得する必要があります。2 つの物理テーブルを、先ほど見つけた仮想テーブルに結合します。

    SELECT A.*, T.*
      FROM (
             SELECT T.ARTIST_ID, MIN(T.TRACK_ID) TRACK_ID
               FROM (
                        SELECT ARTIST_ID, MAX(`TIMESTAMP`) `TIMESTAMP`
                          FROM TRACKS
                      GROUP BY ARTIST_ID
                     ) L
               JOIN TRACKS T ON (    L.ARTIST_ID   = T.ARTIST_ID 
                                 AND L.`TIMESTAMP` = T.`TIMESTAMP`)
           GROUP BY T.ARTIST_ID
           ) X
      JOIN ARTISTS A ON X.ARTIST_ID = A.ARTIST_ID
      JOIN TRACKS  T ON (X.TRACK_ID = T.TRACK_ID AND X.ARTIST_ID = T.ARTIST_ID)
  ORDER BY A.NAME

次のように考えてください。データを含むいくつかの物理テーブルがあります。サブクエリを使用して仮想テーブルを作成し、それらをクエリにネストして含めることで、物理テーブルのように使用することもできます。そのネストは、構造化照会言語と呼ばれる理由の 1 つです。

これが効率的に機能するには、TIMESTAMP、ARTIST_ID、および TRACK_ID 列にインデックスが必要になります。

編集: 最近アップロードされたトラックをどのように明確に取得するかを理解するには、質問のスキーマに関する十分な情報が実際にはありません。

TRACK_ID が TRACKS テーブルの自動インクリメント主キーである場合は、簡単です。アーティストに結合されたままの最大番号のトラック ID を取得します (アーティスト テーブルに対応する行がない場合は、結合されたままになります)。

        SELECT T.*, A.*
          FROM TRACKS T
     LEFT JOIN ARTISTS A ON T.ARTIST_ID = A.ARTIST_ID
      ORDER BY T.TRACK_ID DESC
         LIMIT 1

TRACK_ID が自動インクリメントの主キーではないが、2 つのタイムスタンプが同じになることはほとんどない場合は、これを行います。タイムスタンプが同じトラックが 2 つ以上ある場合は、そのうちの 1 つを任意に選択します。

        SELECT T.*, A.*
          FROM TRACKS T
     LEFT JOIN ARTISTS A ON T.ARTIST_ID = A.ARTIST_ID
      ORDER BY T.`TIMESTAMP` DESC
         LIMIT 1

このデータの秘訣は、必要なものを正確に指定するように細心の注意を払うことです。あなたの質問から、各アーティストの最新のトラックをループで順番に取得しようとしていることは明らかです。私のクエリは、あなたのプログラムでループなしでそれを行いました。しかし、ご存知のとおり、すべての列の名前がわからないため、SQL が完全ではない可能性があります。

于 2012-08-18T14:48:01.280 に答える
1

artistsテーブルとtracksテーブルの関係は ですone-to-many。したがって、tracksテーブルには、この列をテーブル内の列と相互参照する列および外部artist_idキー制約が必要です。これが完了すると、最新のトラックを取得するクエリは次のようになります。idartists

SELECT id, name, url, MAX(timestamp) timestamp
FROM tracks
GROUP BY artist_id
于 2012-08-18T15:02:11.953 に答える
0

これを手伝ってくれた@OllieJonesと@hookmanに感謝します。必要なクエリを見つけました。両方のおかげで、PHP を使用せずにすべてを 1 つのクエリで実行できました。

とにかくここにあります。

SELECT T.url, A.ID, T.ID
FROM tracks T
LEFT JOIN ARTISTS A ON T.ID = A.ID
WHERE T.ID = A.ID
ORDER BY T.timestamp DESC                                      
LIMIT 1

@OllieJones クエリの多くを取得し、少し編集しました。アーティストのみが選択されるように WHERE 句を追加し、必要なデータのみが返されるように * を削除しました。また、@hookman のアドバイスを受けて、大量の外部キーを使用しました。今後も大いに役立ちます。

于 2012-08-18T23:23:31.230 に答える