2012-08-17 169 views
3

我有很多用標籤「狗」標記的文章。我有一個新的標籤,現在叫做「貓」。我想將標籤「cat」添加到所有已有標籤「dog」的文章中。一些文章有兩個標籤。我不想用「貓」來代替這些。如何將所有這些MySQL查詢合併爲一個?

換句話說,如果一篇文章有​​標籤「狗」,但還沒有標籤「貓」,我想給它添加標籤「貓」。這裏是我寫的腳本:

<?php 

    # Get "cat" tag id 
    $sql = "SELECT `id` 
      FROM tags 
      WHERE name = 'cat' 
      LIMIT 1"; 

    $cat_tag = mysql_fetch_assoc(mysql_query($sql)); 

    # Get "dog" tag id 
    $sql = "SELECT `id` 
      FROM tags 
      WHERE name = 'dog' 
      LIMIT 1"; 

    $dog_tag = mysql_fetch_assoc(mysql_query($sql)); 

    ###################################### 

    # Get all nodes tagged with "dog" 
    $sql = "SELECT `node_id` 
      FROM node_tags 
      WHERE `tag_id` = '" . $dog['id'] . "'"; 

    $query = mysql_query($sql); 
    while($row = mysql_fetch_assoc($query)) { 

     # Check to see if current node has "cat" tag already  
     $sql = "SELECT COUNT(*) 
       FROM node_tags 
       WHERE `node_id` = '" . $row['node_id'] . "'   
       AND `tag_id` = '" . $cat['id'] . "'"; 


     $check_already_exists = mysql_fetch_assoc(mysql_query($sql)); 

     # If node doesn't already have "cat" tag, then add it 
     if($check_already_exists == '0') { 
      $sql = "INSERT INTO `node_tags`(node_id, tag_id) 
        VALUES('" . $row['node_id'] . "', '" . $cat['id'] . "')"; 
      mysql_query($sql); 
     } 
    } 

?> 

我希望能夠直接從我的MySQL管理器工具運行。所以它不能有任何PHP,但應該是一個大的SQL查詢。這個怎麼做?

回答

0

以下查詢獲取所有沒有貓ID的「狗」。然後,將它們插入到表:

insert into node_tags(node_id, tag_id) 
    SELECT id, $cat['id'] 
    FROM tags t join 
     node_tags nt 
     on t.node_id = nt.node_id 
    WHERE t.name = 'dog' 
    group by id 
    having max(case when tag_id = $cat['id'] then 1 else 0 end) = 0 
+0

我相當肯定這是行不通的,因爲你試圖讀取並在同一時間從'node_tags'寫。 – 2012-08-17 17:24:51

+0

@Kinkink。 。 。這不是我經歷過的限制。你有文件嗎?應該運行的方式是首先運行「select」,然後插入行。事實上,Mysql 5.5文檔明確指出這是可能的(http://dev.mysql.com/doc/refman/5.5/en/insert-select.html)。 – 2012-08-17 17:29:10

+0

我只是嘗試了一個簡單的'插入到x(y)從x'中選擇y + 10並且得到了「Can not reopen x」錯誤消息。 - 編輯沒關係,我的'x'是一個臨時表,這是不允許的。 – 2012-08-17 17:30:26

0

你不能這樣做在一個查詢中,因爲你需要插入依賴於從同一個表中選擇數據。你可以得到的最接近的是這樣的,假設你有(node_id,tag_id)定義的唯一鍵值:

CREATE TEMPORARY TABLE `tmp` (`node_id` TEXT, `tag_id` TEXT); # Choose better column types if possible 
INSERT INTO `tmp` SELECT `node_id`, `tag_id` FROM `node_tags`; 
SET @id_cat = (SELECT `id` FROM `tags` WHERE `name`='cat'), 
    @id_dog = (SELECT `id` FROM `tags` WHERE `name`='dog'); 
INSERT IGNORE INTO `node_tags` (`node_id`, `tag_id`) 
    SELECT `node_id`, @id_cat FROM `tmp` WHERE `tag_id`[email protected]_dog 
    UNION 
    SELECT `node_id`, @id_dog FROM `tmp` WHERE `tag_id`[email protected]_cat; 
DROP TABLE `tmp`; 

您可以粘貼到你的MySQL管理器工具,它應該工作。

+0

我收到一個錯誤:無法重新打開tmp。 – TK123 2012-08-17 17:43:47

0

,您可以根據在選擇子句中插入:

INSERT INTO node_tags (node_id, tag_id) 
SELECT node_id, (SELECT MAX(id) FROM tags WHERE name = 'cat') 
FROM node_tags 
WHERE tag_id = (SELECT MAX(id) FORM tags WHERE name = 'dog') 

做一個備份您嘗試這樣的事情之前,

+0

因嘗試同時讀取和寫入'node_tags'而失敗。 – 2012-08-17 17:25:50

+0

我相信SGDB會在所有的選擇和插入之後進行插入,但是在這種情況下,他可以將選擇結果放在一個php數組中,並在插入一個表之後進行一段時間。 – 2012-08-17 17:38:17

+0

查看Gordon Linoff的答案,我做了測試,但錯過了臨時表的一個重要因素。 – 2012-08-17 17:39:05

0

)試試這個查詢。我沒有測試過這個。但我認爲這將起作用。

INSERT into node_tags(node_id, tag_id) 
(SELECT node_id, tag_id 
FROM node_tags nt , tags t 
where t.id = nt.tag_id AND t.name = 'dog' 
AND nt.node_id NOT IN (SELECT t1.id FROM node_tags nt1, tags t1 
where nt1.node_id = nt.node_id AND t1.id = nt1.tag_id AND t1.name = 'cat') 
) 
+0

@ JakeRow123:它適合你嗎? – 2012-08-18 18:38:36

0

首先更改您的表並將(node_id和tag_id)合在一起UNIQUE,因爲這就是您所需要的。

ALTER TABLE `node_tags` ADD UNIQUE (`node_id`,`tag_id`); 

這是您的查詢:

$sql = "INSERT IGNORE INTO `node_tags` 
     SELECT (SELECT `node_id` FROM node_tags WHERE EXISTS (SELECT tags.* FROM tags WHERE node_tags.`tag_id` = tags.`id` AND tags.name = 'dog') LIMIT 1), 
       (SELECT `id` FROM tags WHERE name = 'cat' LIMIT 1)";