2011-10-20 90 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) 
相关问题