2012-03-21 97 views
0

我目前的數據庫結構:MySQL的:規範化和表加入了標籤功能

 `images`   `tags`    `images_tags` 
________________ ______________ ________________________ 
| id | title  | | id | name | | id | image_id | tag_id | 
|----|-----------| |----|---------| |----|----------|--------| 
| 1 | Ivysaur | | 1 | fire | | 1 |  2 | 1 | Charizard: fire 
| 2 | Charizard | | 2 | flying | | 2 |  2 | 2 | Charizard: flying 
| 3 | Squirtle | | 3 | water | | 3 |  1 | 4 | Ivysaur: grass 
| 4 | Pidgey | | 4 | grass | | 4 |  4 | 2 | Pidgey: flying 
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 

我想輸出變量與它們各自的值(名稱)。

if ($_GET["pokemon"] == "2") { 
    // output Charizard's tags: fire, flying 
} 

但我很努力想出一個適當的查詢來做到這一點。 INNER JOIN對我不熟悉,對它的工作原理的解釋會非常有幫助。

回答

1

口袋妖怪。大聲笑!的xD

要輸出標籤:

從標籤表和別名爲 「T」
  • 加入第三個表(協會)以別名 「r」 和有R
    SELECT t.id, t.name 
    FROM tags AS t 
        INNER JOIN images_tags AS r ON r.tag_id =t.id 
        INNER JOIN images AS i ON r.image_id =i.id 
    WHERE i.id ='2' 
    
    1. 選擇。 TAG_ID = t.id
    2. 加入圖像表與別名「i」和與r.image_id = i.id
    3. 最後設置過濾器:i.id =「2」(但會mysql_real_escape_string($_GET['pokemon'])因爲你做不想SQL注入)

    現在的快捷方式:

    if(isset($_GET['pokemon')) { 
        $image_id = (int) $_GET['pokemon']; 
        $r = mysql_query("SELECT t.* FROM tags t, tags_images r WHERE r.tag_id =t.id AND r.image_id ='$image_id'"); 
        while($tag = mysql_fetch_assoc($r)) { 
         echo $tag['name'] . '<br />'; 
        } 
    } 
    
  • +1

    你真的應該停止推廣'mysql_ *'API。它已經超過10年了,不應該用於編寫新的代碼。我們有[PDO](http://php.net/pdo)和[MySQLi](http:// php。net/mysqli)與現在已準備好的語句。 – 2012-03-21 01:09:13

    +0

    我實際上不使用它,因爲我依賴於框架。但好點。 – 2012-03-21 01:33:06

    1

    良好的架構設計,您的查詢看起來像:

    SELECT t.* 
    FROM tags AS t 
    INNER JOIN image_tags AS it ON it.tag_id = t.id 
    WHERE it.image_id = 2; 
    

    內加入簡單的說就是在標記表中的任何行,必須有一個相應的在image_tags表中的行。

    1

    對於當前的表結構:

    SELECT 
        tags.name 
    FROM tags 
        LEFT JOIN image_tags ON tags.id = images_tags.tag_id 
        LEFT JOIN images ON images_tags.image_id = images.id 
    WHERE images.id = 2 
    

    ,但我會建議你做在結構上的一些變化。

    1. 擺脫image_tags.id ..這是毫無意義的。您可以根據tag_id和image_id的組合創建composite primary key

    2. stop anonymous id column。人們習慣於從糟糕的教程和更差的ORM庫中獲取無用的習慣。 tags表的ID在tagsimage_tags表中都應該具有相同的名稱。它會使你的數據庫結構,更容易執行,並有一個額外的振作爲查詢:

      SELECT 
          tags.name 
      FROM tags 
          LEFT JOIN image_tags USING(tag_id) 
          LEFT JOIN images USING(image_id) 
      WHERE images.image_id = 2 
      

    使得它如此更容易閱讀..你不覺得..

    要了解JOIN聲明如何工作,this article可能會有所幫助。另外,我會推薦閱讀SQL Antipatterns

    +1

    當然你在開玩笑說第一點?你有沒有必要從超過2列的鏈接表中刪除?這是一場噩夢。重構爲簡單查詢的#2模式並不是一個好主意。 – 2012-03-21 00:40:09

    +0

    So Doctrine是一個更糟糕的ORM? -'-' – 2012-03-21 00:48:08

    +0

    @MikePurcell,我不明白在刪除一個唯一的條目時如何擺脫無意義的列有什麼區別?! #2的要點是創建更易理解的命名約定,簡單的查詢只是一個額外的優點。 – 2012-03-21 01:03:22