PDA

View Full Version : [SQL] Delete senza primary KEY


holymind
26-11-2010, 08:59
Ciao avevo un quesito...

Avrei bisogno di effettuare la delete a parita di id del campo piu' vecchio ma ho difficolta in quanto al momento la tabella non ha primary key...

Esempio

ID DATA
1 15/10/2010
1 13/10/2010
2 14/10/2010
2 12/10/2010


Io voglio che rimangano solo
ID DATA
1 15/10/2010
2 14/10/2010

gugoXX
27-11-2010, 14:45
Quale motore?

Inoltre non hai specificato cosa vorresti rimanesse nel caso in cui le date a parita' di ID fossero piu' di due
ID DATA
1 15/10/2010
1 13/10/2010
1 18/10/2010
1 12/10/2010
2 14/10/2010
2 12/10/2010

oppure, cosa ancor peggiore, se non ci sono constraint di univocita' cosa vorresti in questo caso
ID DATA
1 15/10/2010
1 13/10/2010
1 15/10/2010
2 14/10/2010
2 12/10/2010

Supdario
27-11-2010, 15:17
Ciao avevo un quesito...

Avrei bisogno di effettuare la delete a parita di id del campo piu' vecchio ma ho difficolta in quanto al momento la tabella non ha primary key...

Esempio

ID DATA
1 15/10/2010
1 13/10/2010
2 14/10/2010
2 12/10/2010


Io voglio che rimangano solo
ID DATA
1 15/10/2010
2 14/10/2010

Questo sarebbe possibile se la data fosse indicata in formato Unix, ma se è sotto forma di testo non penso si possa fare (o per lo meno è molto difficile).

Dânêl
28-11-2010, 09:36
non ho modo qui di testare la query, ma di primo acchitto penso potresti fare una cosa del genere:
1) Effettuare una select degli id e max(data) con un group by id:

Select id,max(data) as data FROM TUATABELLA GROUP BY id

2) Questa tabella conterrà solo gli elementi che vuoi mantenere. Ti basta eliminare tutti gli elementi di TUATABELLA che non sono presenti nel risultato della query precedente.

Dovrebbe fare al caso tuo dato che devi mantenere solo gli elementi con la data più recente. Non hai problemi derivanti dalla data espressa come stringa (anche se una conversione in unix_timestamp è sempre possibile al volo) e funziona anche nel caso in cui ci siano più di due elementi con lo stesso id

gugoXX
28-11-2010, 12:29
Se fosse stringa e non data,
15/04/2008 e' maggiore di 13/10/2010
Con conseguenza di certo grave errore.

Comunque hoi chiesto ragguagli perche' magari lui vorrebbe solo cancellare il piu' vecchio, quando nella tua soluzione mantieni solo il piu' nuovo.
In piu' ci fossero piu' elementi con lo stesso ID ne riulterebbe una query che potenzialmente restituirebbe piu' risultati per lo stesso ID.
Se tale fatto fosse scappato e tale query venisse messa in JOIN con qualcos'altro, di nuovo molto probabilmente ne deriverebbero gravi errori.

Dânêl
28-11-2010, 13:09
Se fosse stringa e non data,
15/04/2008 e' maggiore di 13/10/2010
Con conseguenza di certo grave errore.

Ops hai ragione, non so come avevo riflettuto poco fa. Si potrebbe però applicare la funzione STR_TO_DATE() che restituendo la stringa in formato AAAA/MM/GG non dovrebbe soffrire di quel problema (per una conversione in timestamp si dovrebbe comunque passare di qui..)

Comunque hoi chiesto ragguagli perche' magari lui vorrebbe solo cancellare il piu' vecchio, quando nella tua soluzione mantieni solo il piu' nuovo.
Può darsi, ma dalla sua frase penso voglia mantenere solo il più nuovo, a me sembra chiaro, ma posso sempre sbagliarmi :) .
Se, comunque, volesse eliminare il più vecchio in assoluto allora dovrebbe cambiare max con min.

In piu' ci fossero piu' elementi con lo stesso ID ne riulterebbe una query che potenzialmente restituirebbe piu' risultati per lo stesso ID.
Non ho chiaro questo punto.
La tabella originale ha più elementi con lo stesso id, ma la data diversa permette di sfruttare la coppia (id,data) come chiave rendendo univoco il riferimento agli elementi.
La mia query, comunque, restituirebbe un solo elemento per id grazie alla clausola groub by e al fatto che solo un elemento può avere la data più recente.
Non trovo il problema :stordita:

Se ti riferisci alla possibilità che ci possano essere due elementi con stesso id e stessa data, la query restituirebbe sempre e soltanto un risultato per id. Ci sarebbero altri problemi (a meno che non sia una cosa voluta, anche se dubito) dall'avere elementi duplicati, ma andrebbero prevenuti in fase di progettazione ed inserimento.

holymind
29-11-2010, 13:39
Specifico altri dettagli del problema.

- Il DB e' Oracle 9.2.0.7.0
- Il campo data e' un timestamp. Non ho problemi a confrontare due date tra loro
- Ho necessita' che rimanga solo il piu' recente, e vorrei trascurare il caso che abbiamo lo stesso timestamp, ipotizziamo non ce ne siano.

- Sono in grado di selezionare con la select i campi interessati, ma ho difficolta' a cancellarli con il comando delete proprio a causa della mancanza di un campo univoco

gugoXX
29-11-2010, 16:35
DELETE FROM tabella
WHERE (ID, DATA) NOT IN
(SELECT ID,Max(DATA) FROM tabella GROUP BY ID)


Questa dovrebbe andare.

holymind
29-11-2010, 17:19
Grazie mille... Funziona...
Ignoravo che si potesse mettere una coppia di valori in una where...

gugoXX
29-11-2010, 22:11
Sono le set operations, e non tutti i DB le supportano.
In realta' quasi nessuno.
Ma si puo' supplire con la EXISTS.

DELETE FROM tabella extern
WHERE NOT EXISTS (
SELECT 1 FROM (SELECT ID, Max(data) dt FROM tabella GROUP BY ID) as intern
WHERE intern.ID=extern.ID and intern.dt=extern.data
)