2017-12-07 2 views
1

アルバムの表紙にランダムイメージを選択したいと思います。アルバムに「cover」とタグ付けされた画像が含まれている場合は、その画像のみから選択する必要があります。サブアルバムの画像に「cover」とタグ付けされた画像がある場合、「cover」でタグ付けされていない画像は選択しないでください。SQLのランダムイメージカバーを選択

ここには視覚的な構造があります。

Album 1 
├───Image 1 
├───Album 2 
│ ├───Image 2 
│ ├───Image 3 (cover) 
│ └───Image 4 (cover) 
└───Album 3 
    ├───Image 5 
    └───Image 6 
    イメージから選択するべき画像3、画像4
  • アルバム3から選択べき画像1、画像3、画像4、画像5、画像6
  • アルバム2から選択すべき
  • アルバム1 5、画像6ここ

である私のテーブル

表タグ

012これは私が思いついたSQLです

| id | album_id | image_id | 
|----|----------|----------| 
| 1 | 1  | 1  | 
| 2 | 2  | 2  | 
| 3 | 2  | 3  | 
| 4 | 2  | 4  | 
| 5 | 3  | 5  | 
| 6 | 3  | 6  | 

表アルバム

| id | name | parent_id | 
|----|---------|-----------| 
| 1 | album 1 | null  | 
| 2 | album 2 | 1,  | 
| 3 | album 3 | 1,  | 

album_image

| id | name | 
|----|-------| 
| 1 | cover | 

表IMAGE_TAG

| id | image_id | tag_id | 
|----|----------|--------| 
| 1 | 3  | 1  | 
| 2 | 4  | 1  | 

表。

SELECT ai.image_id AS image_id FROM albums AS a 
INNER JOIN album_image AS ai ON ai.album_id = a.id 
LEFT JOIN image_tag AS it ON it.image_id = ai.image_id AND it.tag_id = 1[1] 
WHERE a.id = 1[2] OR parent_id LIKE '1,%'[3] 
ORDER BY CASE 
    WHEN it.tag_id IS NOT NULL AND a.id = 1[4] THEN RAND() 
    ELSE RAND() + 1 
END ASC LIMIT 1; 

[1]:これは現在PHPで別のSQLによって取得されています。マージできるといいですね。 INNER JOINテーブルをLEFT JOINすることは可能ですか?タグが存在しない場合はどうなりますか?

[2]、[4]:これはPHPのアルバムIDです。

[3]:これは、サブアルバムが含まれていることをPHPから取得したものです。

解決策は次の結果を生成します。

  • アルバム1は、選択すべき画像3、画像4
  • アルバム3から選択べき画像1、画像2、画像3、画像4、画像5、画像6
  • アルバム2から選択しなければなりませんイメージ5、イメージ6から

私の期待した結果を生成できるようにSQLを変更する方法はありますか?

P.S.私はMySQLを実行しています。テスト

CREATE TABLE tags (
    id INT AUTO_INCREMENT PRIMARY KEY, 
    name TEXT NOT NULL 
); 
INSERT INTO tags (name) VALUES ('cover'); 

CREATE TABLE image_tag (
    id INT AUTO_INCREMENT PRIMARY KEY, 
    image_id INT NOT NULL, 
    tag_id INT NOT NULL 
); 
INSERT INTO image_tag (image_id, tag_id) VALUES (3, 1); 
INSERT INTO image_tag (image_id, tag_id) VALUES (4, 1); 

CREATE TABLE album_image (
    id INT AUTO_INCREMENT PRIMARY KEY, 
    album_id INT NOT NULL, 
    image_id INT NOT NULL 
); 
INSERT INTO album_image (album_id, image_id) VALUES (1, 1); 
INSERT INTO album_image (album_id, image_id) VALUES (2, 2); 
INSERT INTO album_image (album_id, image_id) VALUES (2, 3); 
INSERT INTO album_image (album_id, image_id) VALUES (2, 4); 
INSERT INTO album_image (album_id, image_id) VALUES (3, 5); 
INSERT INTO album_image (album_id, image_id) VALUES (3, 6); 

CREATE TABLE albums (
    id INT AUTO_INCREMENT PRIMARY KEY, 
    name TEXT NOT NULL, 
    parent_id TEXT 
); 
INSERT INTO albums (name, parent_id) VALUES ('album 1', NULL); 
INSERT INTO albums (name, parent_id) VALUES ('album 2', '1,'); 
INSERT INTO albums (name, parent_id) VALUES ('album 3', '1,'); 

答えて

0

ため

EDIT スキーマは、ここに私のソリューションです。

SELECT ai.image_id AS image_id, (
    SELECT COUNT(*) FROM albums AS a2 
     INNER JOIN album_image AS ai2 ON ai2.album_id=a2.id 
     LEFT JOIN image_tag AS it2 
      INNER JOIN tags AS t2 ON t2.id = it2.tag_id 
     ON it2.image_id = ai2.image_id AND t2.name = 'cover' 
     WHERE a2.id = a.id AND t2.name IS NOT NULL AND it.tag_id IS NULL 
    ) AS count FROM albums AS a 
INNER JOIN album_image AS ai ON ai.album_id=a.id 
LEFT JOIN image_tag AS it 
    INNER JOIN tags AS t ON t.id = it.tag_id 
ON it.image_id = ai.image_id AND t.name = 'cover' 
WHERE a.id = 1 OR parent_id LIKE '1,%' 
ORDER BY CASE 
    WHEN it.tag_id IS NOT NULL AND a.id = 1 THEN RAND() 
    WHEN count > 0 THEN RAND() + 2 
    ELSE RAND() + 1 
END ASC LIMIT 1;