2011-10-20 14 views
5

Ho una tabella nel mio database MySQL chiamato "figli". In quella tabella c'è una riga chiamata "desideri" (una lista separata da virgole degli articoli della lista dei desideri del bambino). Devo essere in grado di aggiornare quell'elenco in modo che rimuova solo un valore. vale a dire la lista = jeans normali taglia 12, tavola da surf, berretto da baseball Red Sox; Voglio rimuovere Tavola da surf.Rimuovere i valori nell'elenco separato da virgola dal database

La mia domanda adesso appare così

$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."'"); 
} 

Ma la query di aggiornamento non è togliere nulla. Come posso fare ciò di cui ho bisogno?

+5

Penso desideri dovrebbero essere di essa la propria tavola e collegata di nuovo qui condividendo il caseNumber chiave. –

+0

Sembra che manchi la concatenazione di una stringa, ma una volta che viene ordinato, si lascia questa query aperta a SQL Injection: un hacker otterrebbe davvero ciò che desiderava. – Andrew

+0

@Daren: questa è davvero la risposta giusta, il modello DB è sbagliato e deve essere corretto. I voti positivi sui commenti non contano – Andrew

risposta

3

Utilizzando these user-defined REGEXP_REPLACE() functions, si può essere in grado di sostituirlo con una stringa vuota:

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

Purtroppo, non si può semplicemente utilizzare Plain Old REPLACE() perché non si sa dove nella stringa appare 'Surfboard'. In effetti, la regex di cui sopra avrebbe probabilmente bisogno di ulteriori ritocchi se "Tavola da surf" si verifica all'inizio o alla fine.

forse si potrebbe tagliare iniziali e finali virgole lasciati come questo:

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

Allora, cosa sta succedendo qui? L'espressione regolare rimuove la 'Tavola da surf' più uno spazio opzionale della virgola & prima di esso. Quindi la funzione TRIM() circostante elimina una possibile virgola iniziale nel caso in cui "Tavola da surf" si sia verificata all'inizio della stringa. Probabilmente questo potrebbe essere gestito anche dal regex, ma francamente sono troppo stanco per risolvere il problema.

Nota, Non l'ho mai usato io stesso e non posso garantire la loro efficacia o robustezza, ma è un punto di partenza. E, come altri menzionano nei commenti, dovresti proprio averli in una tabella delle liste di desideri normalizzata, piuttosto che come una stringa separata da virgole.

Aggiornamento

Pensando a questo di più, sono più parziale forzando solo l'uso di built-in REPLACE() e poi ripulire la virgola in più dove si possono ottenere due virgole di fila. Questo è alla ricerca di due virgole affiancate, come se non ci fossero stati spazi che separano gli elementi della lista originale. Se gli elementi sono stati separati da virgole e spazi, modificare ',,' in ', ,' nella chiamata esterna REPLACE().

1

Non esattamente una risposta diretta alla tua domanda, ma come dice Daren, è meglio avere desideri come tavolo. Forse si potrebbe modificare lo schema del database in modo da avere 3 tavoli, per esempio:

children 
-> caseNum 
-> childName 

wishes 
-> caseNum 
-> wishId 
-> wishName 

childrensWishes 
-> caseNum 
-> wishId 

Poi, per aggiungere o eliminare un desiderio di un figlio, basta aggiungere o eliminare la riga corrispondente da childrensWishes. Il tuo attuale design rende difficile la manipolazione (come stai trovando), inoltre ti lascia a rischio di dati incoerenti.

Come risposta più diretta, è possibile correggere il proprio modo corrente richiamando l'elenco dei desideri, esplodandolo(), rimuovendo quello che non si desidera dall'array e implodificandolo() restituendolo a una stringa per aggiornare il database.

0

fare i desideri tabella ha questo formato:

caseNumber,wish 

Quindi si ottiene tutti i desideri di un bambino come questo:

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

Rimozione di un desiderio diventa:

DELETE from wishes where caseNumber = ? 

Aggiunta di un desiderio diventa:

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

Tornando un desiderio diventa:

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

Avere i desideri indicizzati in un array, che viene successivamente serializzato potrebbe essere un'idea, altrimenti si avrebbe bisogno di recuperare la stringa, tagliatelo a fette, togliere la parte che si don' voglio, quindi concatenare i resti. Questo può essere fatto usando la funzione explode().

Se si sceglie di usare un array, si dovrebbe recuperare la matrice e quindi ordinare attraverso di essa con un ciclo come questo:

// 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 

Tenete a mente che indice [1] ora non esisterà nel array, quindi se si desidera avere una matrice pulita si dovrebbe scorrere l'array e renderlo creare un nuovo array di per sé:

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

Penso che la risposta migliore a tale problema è qui The best way to remove value from SET field?

query dovrebbe essere simile a questo che copre il valore o il valore, oppure solo valore nella colonna separati da virgola

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

Qui si può avere la condizione in cui clausola. per maggiori dettagli, fare riferimento al link sopra.

0

È possibile creare la funzione in questo modo:

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 

Usando:

SELECT remove_from_set('1,,2,3,4,5,6',1) 
Problemi correlati