PDA

View Full Version : [sql] evitare insert di una t-upla già presente


Gregor
22-06-2007, 07:50
Periodicamente eseguo uno script in php per popolare il mio db.
Poichè spesso accade che una t-upla sia già inserita nel db, come posso evitare che venga inserita nuovamente?
E' possibile fare un controllo a livello di db, per non fare un controllo a livello di script in php? Tnx!

rayman2
22-06-2007, 08:03
Intendi dire che non vuoi modificare lo script ma vuoi che il db se ne renda conto e non faccia l'update?
Forse stai parlando di trigger....
ma in realtà non capisco perchè non esegui lo script una volta sola dato che si tratta di popolamento della base di dati!

Matrixbob
22-06-2007, 09:22
Intendi dire che non vuoi modificare lo script ma vuoi che il db se ne renda conto e non faccia l'update?
Forse stai parlando di trigger....
ma in realtà non capisco perchè non esegui lo script una volta sola dato che si tratta di popolamento della base di dati!

I trigger non sono azioni da fare quando capitano certi eventi, quindi ad esempio l'evento "update"?
MySQL li implementa? Fino a poco tempo fa solo PostgreSQL, tra i free, li aveva.

Matrixbob
22-06-2007, 09:23
Periodicamente eseguo uno script in php per popolare il mio db.
Poichè spesso accade che una t-upla sia già inserita nel db, come posso evitare che venga inserita nuovamente?
E' possibile fare un controllo a livello di db, per non fare un controllo a livello di script in php? Tnx!

IMHO
Bisognerebbe modifcare lo script in modo che prima faccia una ricerca di quella tupla e se la ricerca ha esito negativo d'inserirla.
Magari esiste qualche altra MACROISTRUZIONE del DBMS che la risolve con meno smanettamento: ormai i DBMS danno una serie impensabile di possibilità, statistiche ed AI comprese.

CMQ il controllo puramente a livello DB penso sia infattibile in quando il DB si occupa come principio di difendere le regole ACID e basta, quindi se il DB le rispetta lui è a posto.

Tra l'altro se ha la stessa chiave il DBMS non la fa inserire già di default.
Se invece la chiave è 1 seriale allora il problema esiste.

Gregor
22-06-2007, 12:21
Intendi dire che non vuoi modificare lo script ma vuoi che il db se ne renda conto e non faccia l'update?

Esatto, se la t-upla è già presente, allora scartala.


Forse stai parlando di trigger....
ma in realtà non capisco perchè non esegui lo script una volta sola dato che si tratta di popolamento della base di dati!

Perchè lo script, per natura, passa più volte al giorno. E tra i dati da caricare ci possono essere due t-uple uguali.

Gregor
22-06-2007, 12:23
IMHO
Bisognerebbe modifcare lo script in modo che prima faccia una ricerca di quella tupla e se la ricerca ha esito negativo d'inserirla.

Era quello che volevo evitare ;)


Magari esiste qualche altra MACROISTRUZIONE del DBMS che la risolve con meno smanettamento: ormai i DBMS danno una serie impensabile di possibilità, statistiche ed AI comprese.

Eh magari :)


Tra l'altro se ha la stessa chiave il DBMS non la fa inserire già di default.
Se invece la chiave è 1 seriale allora il problema esiste.

L'ID (key) è autoincrementante e non è un valore che gli passo :(

vizzz
22-06-2007, 12:25
fai prima una SELECT count(*) FROM pippo WHERE....
con tutte le condizione che secondo te rendono due tuple uguali.
se torna > 0, non fai la insert

rayman2
22-06-2007, 17:45
L'idea del trigger sarebbe questa (in linea teorica, poi mi spiego meglio):

Crei un trigger nel DBMS che PRIMA di ogni inserimento in una specifica tabella (la tua) controlla PER OGNI RIGA che stai inserendo se esiste già una tupla con le caratteristiche di quella nuova ed eventualmente non effettua l'inserimento.
In una sintassi da me inventata (nel senso che non è codice funzionante ma ci si avvicina):

CREATE TRIGGER nome_trigger BEFORE INSERT ON tua_tabella
FOR EACH ROW
BEGIN
IF (SELECT COUNT(*)
FROM tua_tabella
WHERE NEW.attributo_da_verificare = attributo_da_verificare) > 0 THEN
RETURN FALSE;
END IF;
END;

Problema pratico: tutto dipende dal DBMS, sia la sintassi, sia il supporto ai trigger!
Per MySQL puoi dare un occhio qui: http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html

Inoltre mi sorge un dubbio. La tabella nella quale vai ad inserire quelle tuple, non dovrebbe avere come chiave gli attributi che vorresti non fossero ripetuti?
Mi spiego, la definizione di chiave primaria è proprio quella di essere presente in solo una tupla della tabella. Perchè nella tua non è così?

Altra domanda di curiosità: perchè non modificare lo script? Va bene il puro diletto intellettuale, ma quella è davvero la soluzione più rapida!

Gregor
22-06-2007, 18:28
L'idea del trigger sarebbe questa (in linea teorica, poi mi spiego meglio):

Crei un trigger nel DBMS che PRIMA di ogni inserimento in una specifica tabella (la tua) controlla PER OGNI RIGA che stai inserendo se esiste già una tupla con le caratteristiche di quella nuova ed eventualmente non effettua l'inserimento.
In una sintassi da me inventata (nel senso che non è codice funzionante ma ci si avvicina):

CREATE TRIGGER nome_trigger BEFORE INSERT ON tua_tabella
FOR EACH ROW
BEGIN
IF (SELECT COUNT(*)
FROM tua_tabella
WHERE NEW.attributo_da_verificare = attributo_da_verificare) > 0 THEN
RETURN FALSE;
END IF;
END;


Problema pratico: tutto dipende dal DBMS, sia la sintassi, sia il supporto ai trigger!
Per MySQL puoi dare un occhio qui: http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html

Non ho mai usato un trigger, ma hai reso l'idea tnx! :)


Inoltre mi sorge un dubbio. La tabella nella quale vai ad inserire quelle tuple, non dovrebbe avere come chiave gli attributi che vorresti non fossero ripetuti?
Mi spiego, la definizione di chiave primaria è proprio quella di essere presente in solo una tupla della tabella. Perchè nella tua non è così?

La key è l'id che non viene inserito, essendo autoincrementante.


Altra domanda di curiosità: perchè non modificare lo script? Va bene il puro diletto intellettuale, ma quella è davvero la soluzione più rapida!

Pensavo ad una soluzione più veloce lato DB...ad ogni modo certo che posso modificare lo script ;)

rayman2
22-06-2007, 18:42
E di fare una chiave multipla non se ne parla?
Del tipo, id autoincrementante ed un altro campo che è quello che non deve ripetersi.

Matrixbob
22-06-2007, 18:57
E di fare una chiave multipla non se ne parla?
Del tipo, id autoincrementante ed un altro campo che è quello che non deve ripetersi.

Penso che non debba modificare il DB, altrimenti l'avrebbe fatto.

Gregor
22-06-2007, 20:39
E di fare una chiave multipla non se ne parla?
Del tipo, id autoincrementante ed un altro campo che è quello che non deve ripetersi.

Quesa soluzione non l'ho capita...
Su sei campi (per es.) cinque non devono ripetersi, il sesto è la key della tabella.

rayman2
22-06-2007, 20:55
Ah, no, pensavo fosse uno solo...

Matrixbob
22-06-2007, 20:56
Quesa soluzione non l'ho capita...
Su sei campi (per es.) cinque non devono ripetersi, il sesto è la key della tabella.

Proponeva 1 superchiave composta da + attributi (almeno 2) di cui 1 unico e l'altro il tuo seriale.
Almeno così ho capito.

Ma nemmeno a me ste cose piacciono.

cionci
23-06-2007, 10:45
In teoria basta anche un indice... Se la chiave è un'altra...basta uno unique index su tutti gli altri campi che non vuoi che possano essere ripetuti. In tal caso ritorna un errore in fase di inserimento...
Non credo che sia una soluzione molto performante, ma sicuramente è una soluzione valida.

nuovoUtente86
23-06-2007, 11:35
perdonami potresti lavorare sul concetto di Key,calato nello specificodei tuoi attributi,in modo da delegare al database l' esclusione di tuple uguali.

Gregor
24-06-2007, 15:39
perdonami potresti lavorare sul concetto di Key,calato nello specificodei tuoi attributi,in modo da delegare al database l' esclusione di tuple uguali.

Puoi farmi un esempio?
l'esigenza è quella di evitare (senza interrompere la procedura inviata dallo script php) l'inserimento di t-uple uguali. Servirebbe uno "scavalcamento" e l'inserimento solo delle t-uple diverse anche solo per un campo.
Se lo script si interrompe non va bene, non inserirebbe così le t-uple "buone".

cionci
24-06-2007, 15:52
Come ti ho detto basta creare uno unique index su tutti gli attributi escluso l'id...

Matrixbob
25-06-2007, 10:27
Come ti ho detto basta creare uno unique index su tutti gli attributi escluso l'id...

Non dovrebbe rallentare parecchio l'operazione questo?
CMQ se è 1 cosa fatta ogni tanto è anche accettabile come side effect.

Gregor
25-06-2007, 11:40
Come ti ho detto basta creare uno unique index su tutti gli attributi escluso l'id...

Scusa, però così facendo se mi trovo già nel db la t-upla

id nome cognome anni
1 pippo pluto 25

con key id

e passassi la t-upla

pippo pluto 26

non verrebbe inserita in quanto nome=pippo non sarebbe più unico nel db. O sbaglio?

Tnx!

nuovoUtente86
25-06-2007, 11:47
nn penso si riferisse al dichiarare gli attributi unique...ma piuttosto a ricavare uno o piu indici univoci derivanti dagli attributi della tupla.Ti faccio un esempio grezzo di ciò che farei in java.

attributo1...........attributon
dove attributon=attrinuto1.hashCode()+......+attributon-1.hashCode()...

con buona probabilità dovrebbe garantire inserimenti univoci.

Altrimenti pensandoci bene se tu dichiarassi come key tutti gli attributi avresti cmq inserimenti univoci

riprendendo il tuo esempio

se la chiave è tutta la tupla

Pippo 26.......

è differente da
Pippo 25 per cui l' inserimento va a buon fine.

Matrixbob
25-06-2007, 12:25
Scusa, però così facendo se mi trovo già nel db la t-upla

id nome cognome anni
1 pippo pluto 25

con key id

e passassi la t-upla

pippo pluto 26

non verrebbe inserita in quanto nome=pippo non sarebbe più unico nel db. O sbaglio?

Tnx!
Penso che il controllo sia unico su tutta la tupla e non sui singoli attributi.

Gregor
25-06-2007, 14:00
Penso che il controllo sia unico su tutta la tupla e non sui singoli attributi.

Questo già potrebbe essere un punto di partenza, adesso indago ;)

cionci
25-06-2007, 14:21
Aspettate che vi faccio un esempio :)

cionci
25-06-2007, 14:54
Allora...
Ho creato una tabella di questo tipo:

CREATE TABLE `prova`.`prova` (
`id` int(11) NOT NULL auto_increment,
`Cognome` char(30) NOT NULL,
`Nome` char(30) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unico` (`Cognome`,`Nome`)
) ENGINE=InnoDB;

Quello è uno unique index ;)
Ecco come funziona:

mysql> INSERT INTO prova (Nome, Cognome) VALUES ('Pinco', 'Pallino');
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO prova (Nome, Cognome) VALUES ('Pinco', 'Pallino');
ERROR 1062 (23000): Duplicate entry 'Pallino-Pinco' for key 2

Non permette di inserire una tupla avente i campi dello UNIQUE INDEX uguali (contemporaneamente) a a una delle tuple già presenti.

mysql> INSERT INTO prova (Nome, Cognome) VALUES ('Tizio', 'Pallino');
Query OK, 1 row affected (0.02 sec)

Come potete notare l'indice in questo caso non blocca l'inserimento ;)

nuovoUtente86
25-06-2007, 15:11
Allora...
Ho creato una tabella di questo tipo:

CREATE TABLE `prova`.`prova` (
`id` int(11) NOT NULL auto_increment,
`Cognome` char(30) NOT NULL,
`Nome` char(30) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unico` (`Cognome`,`Nome`)
) ENGINE=InnoDB;

Quello è uno unique index ;)
Ecco come funziona:

mysql> INSERT INTO prova (Nome, Cognome) VALUES ('Pinco', 'Pallino');
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO prova (Nome, Cognome) VALUES ('Pinco', 'Pallino');
ERROR 1062 (23000): Duplicate entry 'Pallino-Pinco' for key 2

Non permette di inserire una tupla avente i campi dello UNIQUE INDEX uguali (contemporaneamente) a quelli delle tuple già presenti.

mysql> INSERT INTO prova (Nome, Cognome) VALUES ('Tizio', 'Pallino');
Query OK, 1 row affected (0.02 sec)

Come potete notare l'indice in questo caso non blocca l'inserimento ;)
si esatto era quello che dicevo proprio io,ora in base ai tuoi attributi devi capire cosa meglio fare con ii tuoi attributi.

Gregor
25-06-2007, 16:28
Allora...
Ho creato una tabella di questo tipo:

CREATE TABLE `prova`.`prova` (
`id` int(11) NOT NULL auto_increment,
`Cognome` char(30) NOT NULL,
`Nome` char(30) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unico` (`Cognome`,`Nome`)
) ENGINE=InnoDB;

Quello è uno unique index ;)


Ottimo! :D
E' proprio quello che cercavo! Tnx!
Mi mancava proprio il concetto di "unique index".
Grazie ancora a tutti quelli che sono intervenuti!

cionci
25-06-2007, 16:50
Di niente ;)