2012-11-20 16 views
7

Ho una tabella che contiene un ID negozio e l'ID di un giocatore, e i punti di un giocatore. Quello che voglio fare è trasferire punti da un negozio all'altro, il fatto è che l'id del negozio e l'id del giocatore formano un indice univoco. Quello che voglio fare è aggiornare la chiave duplicata, invece di lasciarla fallire, aggiungere i punti di una voce all'altra ed eliminare la voce "da". Qualcosa di simile:sull'aggiornamento della chiave duplicata

UPDATE `playerspoints` 
SET `boardId`=$to 
WHERE `boardId`=$from 
ON DUPLICATE KEY UPDATE `points`=.... get the idea? 
+0

La mia ipotesi è che questo sarebbe più semplice con 2 query (ish) e un blocco if/else. C'è una ragione particolare per cui vuoi farlo in questo modo? – landons

+2

Ottenere il massimo dai poteri di una lingua è una buona pratica. Si tratta di scoprire cose e fare le cose nel modo più veloce possibile. –

+0

Spero davvero che questo abbia [il corretto escape di SQL] (http://bobby-tables.com/) se è distribuito in produzione. Vedere variabili nude come queste è preoccupante. – tadman

risposta

3

si può solo fare modifiche nel contesto di una riga in conflitto nella zona ON DUPLICATE KEY. Inoltre, questo è, per quanto ne so, una proprietà della dichiarazione INSERT.

Ciò di cui hai bisogno è una semplice contabilità in cui registrare le aggiunte e le sottrazioni da un saldo, quindi tabulare quelle manualmente o utilizzando i trigger.

Per esempio, l'approccio più semplice è:

INSERT INTO points_adjustments (boardId_from, boardId_to, points) 
    VALUES (?, ?, ?) 

Questo potrebbe essere più facilmente rappresentato come un paio di voci:

INSERT INTO points_adjustments (boardId, points) 
    VALUES (?, ?) 

Faresti aggiungere una voce per + n punti, e uno corrispondente per -n. In qualsiasi momento è possibile ottenere un saldo utilizzando SUM(points). È possibile concludere questo in uno VIEW per semplificare il recupero o, se lo si desidera, denormalizzare le somme in una colonna di un'altra tabella utilizzando un trigger.

Un semplice grilletto avrebbe emesso la seguente dichiarazione per ogni colpiti boardId:

INSERT INTO balances (boardId, points) VALUES (?, ?) 
    ON DUPLICATE KEY SET points=points+VALUES(points) 

Questo evita le collisioni chiave in primo luogo e fornisce un record verificabile delle operazioni che si sono verificati.

In ogni caso, per fare tutto questo automaticamente dovresti probabilmente usare un trigger.

+0

Mi piace questa soluzione, ma non ho mai usato i grilletti prima che sia giunto il momento di farlo. Per quanto riguarda la fuga ... $ da \t = (int) mysql_real_escape_string ($ _ REQUEST ['from']); \t \t \t \t $ a \t = (int) mysql_real_escape_string ($ _ RICHIESTA ['a']); \t \t \t \t $ delete = $ condizione [mysql_real_escape_string ($ _ REQUEST ['delete'])]; \t \t \t \t $ contest = $ condition [mysql_real_escape_string ($ _ REQUEST ['contest'])]; c'è altro che potrei fare? –

+0

Sì. I trigger sarebbero il logico passo successivo. Le eliminazioni automatiche sulle violazioni dei vincoli erano un pensiero ambizioso :) – landons

+0

Sì ... usa PDO (o un'altra libreria di astrazione DB). – landons

0

No. Non è possibile eliminare un record in seguito alla violazione del vincolo in MySQL. È possibile eseguire un trigger di aggiornamento precedente che verifica la presenza di una violazione del vincolo imminente, ma anche in questo caso (a partire da 5.1) non è possibile modificare i dati della stessa tabella (che comunque causerebbe comunque un loop infinito in questo caso).

Solo a metà strada prima della risposta di Tadman. Mi piace la sua idea, personalmente.

Problemi correlati