2011-10-20 125 views
5

我在我的MySQL數據庫中有一個名爲'children'的表。在那張表中有一行叫做「願望」(一個逗號分隔的孩子願望清單項目清單)。我需要能夠更新該列表,以便它只刪除一個值。即名單= 12號普通牛仔褲,Surfboard,Red Sox棒球帽;我想刪除Surfboard。從數據庫中刪除逗號分隔列表中的值

我的查詢現在看起來是這樣的

$select = mysql_query('SELECT * FROM children WHERE caseNumber="'.$caseNum.'" LIMIT 1 '); 
    $row = mysql_fetch_array($select); 

    foreach ($wish as $w) { 
     $allWishes = $row['wishes']; 
     $newWishes = str_replace($w, '', $allWishes); 
     $update = mysql_query("UPDATE children SET wishes='$newWishes' WHERE caseNum='".$caseNum."'"); 
} 

但更新查詢不消除任何。我該如何做我需要的?

+5

我覺得願望應該是它自己的表,並通過共享密鑰caseNumber鏈接回到這裏。 –

+0

看起來缺少1個字符串連接,但一旦得到排序,您將此查詢開放給SQL注入 - 黑客真的會得到他們想要的東西。 – Andrew

+0

@達人 - 這真的是正確的答案,數據庫模型是錯誤的,需要修復。對評論的可憐upvotes不計數 – Andrew

回答

3

使用these user-defined REGEXP_REPLACE() functions,你可以用一個空字符串替換它:

UPDATE children SET wishes = REGEXP_REPLACE(wishes, '(,(\s)?)?Surfboard', '') WHERE caseNum='whatever'; 

不幸的是,你不能只用普通的舊REPLACE(),因爲你不知道在哪裏的字符串「衝浪板」出現。事實上,如果'Surfboard'出現在開頭或結尾,上面的正則表達式可能需要額外的調整。

也許你可以剪掉開頭和結尾留下這樣的逗號:

UPDATE children SET wishes = TRIM(BOTH ',' FROM REGEXP_REPLACE(wishes, '(,(\s)?)?Surfboard', '')) WHERE caseNum='whatever'; 

所以這是怎麼回事呢?正則表達式刪除'Surfboard'加上一個可選的逗號&之前的空間。然後,周圍的TRIM()函數消除了在字符串開頭髮生「衝浪板」的情況下可能的前導逗號。這可能也可以通過正則表達式來處理,但坦率地說,我太累了,無法解決它。

注意,我從來沒有使用過這些東西,也不能擔保它們的有效性或健壯性,但它是一個開始的地方。而且,正如其他人在評論中提到的那樣,你真的應該將這些放在規範化的願望清單表中,而不是用逗號分隔的字符串。

更新

更多這方面的思考,我更偏向於剛強制使用內置REPLACE(),然後清理出額外的逗號,你可以連續獲得兩個逗號。這是並排尋找兩個逗號,好像沒有空格分隔您的原始列表項目。如果項目已用逗號和空格分隔,請在外部REPLACE()調用中將',,'更改爲', ,'

UPDATE children SET wishes = TRIM(BOTH ',' FROM REPLACE(REPLACE(wishes, 'Surfboard', ''), ',,', ',')) WHERE caseNum='whatever'; 
1

不完全直接回答你的問題,但像達人說,這是可以更好地有願望作爲自己的表。也許你可以改變你的數據庫架構讓你有3個表,例如:

children 
-> caseNum 
-> childName 

wishes 
-> caseNum 
-> wishId 
-> wishName 

childrensWishes 
-> caseNum 
-> wishId 

然後添加或刪除希望有一個孩子,你只需要添加或刪除childrensWishes相關行。您目前的設計使操作變得困難(正如您所發現的那樣),並且會使您面臨數據不一致的風險。

作爲一個更直接的答案,您可以通過獲取願望清單來修復您的當前方式,explode()'將它們刪除,將不想從數組中移除的項和implode()'返回一個字符串來更新數據庫。

0

許願表有這樣的格式:

caseNumber,wish 

那麼你得到的所有孩子的願望是這樣的:

SELECT * FROM children c left join wishes w on c.caseNumber = w.caseNumber WHERE c.caseNumber= ? 

刪除願望變爲:

DELETE from wishes where caseNumber = ? 

添加願望變爲:

INSERT into wishes (caseNumber,wish) values (?,?) 

返回一個願望變爲:

SELECT * FROM children c left join wishes w on c.caseNumber = w.caseNumber WHERE c.caseNumber= ? LIMIT 1 
0

有在此後被序列化可能是一個想法,一個數組索引的意願,否則你將需要檢索的字符串,分析它,刪除你不」的一部分不想要,然後連接遺體。這可以通過使用explode()函數來完成。

如果你使用一個數組,你會檢索數組,然後理清其與這樣的循環:

// Wishes array: 
// Array (
//  [0] Regular Jeans 
//  [1] Surfboard 
//  [2] Red Sox Baseball Cap 
//) 

$wishes = $row['wishes']; // This is a serialized array taken from the database 
$wishes = unserialize($wishes); 

foreach ($wishes as $key => $value) { 
    if ($value == 'Surfboard') { 
     unset($wishes[$key]); 
     break; 
    } 
} 

$wishes = serialize($wishes); 
// Update database 

請記住,指數[1]現在不會在存在陣列,所以如果你希望有一個乾淨的數組,你應該遍歷數組,並使其本身創建一個新的數組:

foreach ($wishes as $wishes) { 
    $newArray[] = $wishes; 
} 
0

我認爲最好的答案,這樣的問題是在這裏 The best way to remove value from SET field?

查詢應該是這樣的覆蓋在逗號,價值或價值,或者只看重分離柱

 
UPDATE yourtable 
SET 
    categories = 
    TRIM(BOTH ',' FROM 
     REPLACE(
     REPLACE(CONCAT(',',REPLACE(col, ',', ',,'), ','),',2,', ''), ',,', ',') 
    ) 
WHERE 
    FIND_IN_SET('2', categories) 

在這裏,你可以在where子句中的條件。有關更多詳情,請參閱上述鏈接

0

你可以這樣創建功能:

CREATE FUNCTION `remove_from_set`(v int,lst longtext) RETURNS longtext CHARSET utf8 
BEGIN 
set @lst=REPLACE(@lst, ',,', ','); 
set @lng=LENGTH(@lst) - LENGTH(REPLACE(@lst, ',', ''))+1; 
set @p=find_in_set(@v,@lst); 
set @l=SUBSTRING_INDEX(@lst, ',', @p-1); 
set @r=SUBSTRING_INDEX(@lst, ',', @[email protected]); 
IF @l!='' AND @r!='' THEN 
    return CONCAT(@l,',',@r); 
ELSE 
    RETURN CONCAT(@l,'',@r); 
END IF; 
END 

使用:

SELECT remove_from_set('1,,2,3,4,5,6',1) 
相關問題