Newsgroup: it.comp.www.php
Titolo: aggiornare DB da un file proveniente da altro DB

Salve a tutti,
anche sta settimana sono nella melma.
Vi spiego il quid:
in pratica io ho 2 softwares, uno che chiamo ADMIN
e l'altro che chiamo AGENTE.
ADMIN gira su un server e genera un file .sql
che mette in una sua cartella chiamata BKP.
AGENTE, tramite uno script che ho fatto, anche grazie
ad Alessandro Pellizzari (grazie infinite per gli input),
da remoto accede a questa cartella BKP, scarica il file .sql
e....
Ecco qui mi sono fermato, perchï¿œ in pratica ciï¿œ che AGENTE deve
fare dopo aver scaricato il file ï¿œ aggiornare il suo MySQL.
Come posso farglielo fare?
Da considerare che le chiavi primarie delle tabelle dumpate
nel file .sql non corrispondono ai valori che trovo nel DB
di AGENTE, per cui bisognerebbe evitare una "sovrascrittura".
Di nuovo quindi vi chiedo: link, suggerimenti, tutorials,
eventuali soluzioni fast?
Mille grazie a tutti
Franz

 eventuali soluzioni fast?
Non puoi fare in modo che ADMIN ogni volta che aggiorna una tabella scriva anche
(da qualche parte: campo TEXT, file di testo...) una riga MySQL gia' pronta per
essere data in pasto ad AGENTE?
Ogni tanto ti vai a leggere quel file (o quel campo), lo seghi da ADMIN e lo
esegui su AGENTE.
Una sorta di sincronia remota asincrona (che sembra un po' una supercazzola).
Ciao,
luigi
-- 
/
+--[Luigi Rosa]--
\
Psychologists think they're experimental psychologists.
Experimental psychologists think they're biologists.
Biologists think they're biochemists.
Biochemists think they're chemists.
Chemists think they're physical chemists.
Physical chemists think they're physicists.
Physicists think they're theoretical physicists.
Theoretical physicists think they're mathematicians.
Mathematicians think they're metamathematicians.
Metamathematicians think they're philosophers.
Philosophers think they're gods.

 esegui su AGENTE.
Ciao Luigi
allora, adesso in pratica io ho un file proveniente da ADMIN che
non ï¿œ altro che un dump .sql il quale contiene anche istruzioni di
DROP e CREATE TABLE.
A me va bene che vengano distrutte e ricreate le tabelle.
se faccio un echo file_get_contents(htmlspecialchars($fileSQL))
ottengo a video tutto il file. (giusto per debug)
Se apro una connessione al DB e gli do in pasto
$query = file_get_contents(htmlspecialchars($dove_scaricare))
ottengo "INVALID QUERY".
Immagino che sia perchï¿œ ogni riga del file .sql finisce con ;
o perchï¿œ magari non si possono mandare piu di una istruzione in pasto
al DB.
Come posso superare questo scoglio?
Grazie
Franz

 $query = file_get_contents(htmlspecialchars($dove_scaricare))
Non puo' funzionare perche' il buffer della query non e' infinito; e' lo stesso
motivo per cui quando ficchi un file uuencodato in una tabella MySQL devi farlo
a pezzi
Hai due possibilita' IMHO:
* ti leggi l'intero file, lo fai a pezzi con explode() o altri sistemi basandoti
sui ';' e dai in pasto a MySQL un pezzo alla volta
* esegui un "mysql -p... -u.... < nomefile" in shell
Ciao,
luigi
-- 
/
+--[Luigi Rosa]--
\
Per fare molte cose bisogna non avere tempo.
    --Lino Toffolo

 di AGENTE, per cui bisognerebbe evitare una "sovrascrittura".
Se non ï¿œ un problema riallineare le PK di AGENTE risolvi tutto con una 
sola riga di shell (non serve nemmeno il PHP):
mysql --user=UserName --password=Password --force < nomefile.sql
Ovviamente nel file nomefile.sql devono essere presenti tutte le 
istruzioni di cambiamento DB, le DDL di eliminazione/creazione tabelle e 
di inserimento record...
Se invece cambiare le tabelle di AGENTE ï¿œ un problema devi leggere il 
file nomefile.sql "una istruzione SQL alla volta", la vedo molto piï¿œ 
complicata...
La (prima) soluzione che ti suggerisce Luigi Rosa ("pezzi con explode() 
basandoti sui ';'") puï¿œ non funzionare se, all'interno delle istruzioni 
DML, ci sono degli inserimenti che contengono stringhe con il carattere 
";" usato per la separazione con explode()...
Ti consiglio di modificare le tabelle di AGENTE :-)
JM

 ";" usato per la separazione con explode()...
Era scritta alla veloce.
A memoria, mysqldump termina gli statement con un ';' e un a-capo.
Ciao,
luigi
-- 
/
+--[Luigi Rosa]--
\
The world potential market for copying machines is 5000 at most.
       --IBM, 1959

 
Ciao Jimmy, cosa intendi per riallineare le public key?
Se ho una tabella con il campo id che arriva a N e voglio importare
un file (anch'esso con id che arriva a N) che mi fa una serie di insert 
proveniente da un altro DB, come faccio ad ignorare il campo ID e fargli
"appendere" i nuovi record in coda a id = N?
Non so se sono stato chiaro.
Se risolvo sta questione, diciamo che avrei una soluzione alternativa
al mio problema.
Grazie
Franz

naturalmente volevo scrivere Private KEy e non public...
:)

 mysql --user=UserName --password=Password --force < nomefile.sql
questa ï¿œ una delle tabelle che voglio aggiornare:
CREATE TABLE `competitor` (
   `idcompe`     int(8) UNSIGNED AUTO_INCREMENT NOT NULL,
   `competitor`  varchar(128) NOT NULL,
   `note`        mediumtext NOT NULL,
   `impronta`    timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
   /* Keys */
   PRIMARY KEY (`idcompe`)
) ENGINE = MyISAM
   COLLATE `utf8_unicode_ci`;
dal db di ADMIN ho fatto una select into outfile che mi genera:
1,"Illy","no note","2009-07-29 12:30:02"
2,"Lavazza","","2009-07-29 12:29:17"
3,"Saicaf","","2009-07-29 12:29:17"
4,"Vergnano","","2009-07-29 12:29:17"
Se faccio una LOAD DATA INFILE ottengo:
QUERY FALLITA: Data truncated for column 'idcompe' at row 1
Sto impazzendo :(
Questa query non funziona neanche se svuoto la tabella di cui sopra
e la riempio con load data.
Suggerimenti?
Franz

 Sto impazzendo :(
Hai provato aggiungendo
OPTIONALLY ENCLODES BY '"'
Vedi 
http://dev.mysql.com/doc/refman/5.0/en/load-data.html
Ciao,
luigi
-- 
/
+--[Luigi Rosa]--
\
James Bond: Are these pictures live?
M: Unlike the Americans, we prefer not to get our bad news from CNN.
    --"007 Goldeneye"

 Vedi 
http://dev.mysql.com/doc/refman/5.0/en/load-data.html
ti adoro :)
Era quello!!
Ho aggiunto anche un REPLACE, cosi ogni volta mi riscrive il
contenuto della tabella.
Funziona alla grande.
Ora mi piacerebbe creare un batch con queste istruzioni, ma credo che 
non sia il ng adatto questo.
Se poi avete qualche link, ringrazio sentitamente ;-P
Franz

:)
Diciamo che volevi scrivere "primary" :-D
Il problema non ha una soluzione semplice perche' ti trovi in questa
situazione:
source_table		agent_table
pk	value		pk	value
1	uno		1	ein
2	due		2	zwei
3	tre
e vorresti trovarti in quest'altra:
agent_table
pk	value
1	ein
2	zwei
3	uno
4	due
5	tre
Ci potrebbe poi essere un altro problema che e' questo:
source_table	agent_table
pk	value	pk	value
8	otto	12	otto	<----
9	nove	13	hans
Nel primo caso (niente chiavi duplicate) bisogna che intanto tu risolva
il problema dei "reference group". Mi spiego: quando una PK la usi come
join key su un'altra tabella, per esempio
   [IPOTESI UNO: NON HAI TUPLE DUPLICATE]
frutta
1	pera
e
conto
id	id_frutta
15	1		; Questo ha preso una pera
allora la tabella 'conto' fa parte del reference group di frutta:pk, su
id_frutta.
Dopo aver dato una lunga e dura occhiata al database, ti devi trovare a
tiro questi dati:
1. Elenco di tutte le public key interessate (probabilmente TUTTE)
pk_fase_1
table	pkname
conto	id
frutta	id
...
2. Elenco dei reference group
pk_fase_2
table	column		pktable	pkcolumn
conto	id_frutta	frutta	id
Le cose che devi fare a questo punto sono:
a) Unicizzare le PK delle tabelle Agente. Per farlo, se hai tutte PK di
   tipo intero, ti basta sommare a ogni PK Master il massimo pi� uno se
   parti da zero delle PK agente. In MySQL, il massimo direttamente.
   [IPOTESI DUE: TUTTE LE PK SONO INTERE]
b) Riconciliare le reference. Anche qui basta che tu sommi al valore di
   ogni colonna reference il massimo del corrispondente valore della PK
   corrispondente in Agente.
Quindi potresti procedere cosi', ricordando che se non valgono entrambe
le ipotesi sopra, ti trovi in una Fossa delle Marianne di letame suino:
* Importi il database MASTER in un database temporaneo, con CREATE DB e
  CREATE TABLE a rondem�n.
* Per ogni PK, su Agente, fai una SELECT MAX() e archivi il risultato
* Per ogni PK e reference column, fai UPDATE ... SET key=key+ThisMax
* Ri-esporti il database con sole INSERT, niente CREATE
* Lanci l'export su Agente
* Tronchi il database temporaneo
In teoria tutto cio' si potrebbe anche automatizzate analizzando il DB,
e magari esiste gia' uno script che lo fa, e mi sono appena sparato uno
dei piu' apocalittici rasponi che la Storia ricordi... io, fossi in te,
una googlata la darei ;-)
Leonardo
-- 
The cock doth craw, the day doth daw,
the channerin' worm doth chide:
gin we be mist oot o' oor place,
a sair pain we maun bide.

 Diciamo che volevi scrivere "primary" :-D
diciamo che sto lavorando dalle 7 e sono fuso :)
Si ovviamente volevo scrivere primary, ma siccome ho anche
una cosa in C aperta allora public e private erano nei miei pensieri :)
Franz

Leonardo Serni ha scritto:


Grazie Leonardo,
come ho scritto in risposta a Luigi, ho risolto in un altro modo.
Poich� ADMIN deve dare in pasto a AGENTE un aggiornamento progressivo
allora faccio creare ad ADMIN un file con SELECT INTO OUTFILE, in modo
che mi prenda tutto il contenuto della tabella.
Poi da AGENTE importo il tutto con una LOAD DATA INFILE REPLACE, che
in pratica, mi sovrascrive le righe duplicate.
In questo modo in AGENTE ho una copia speculare del contenuto della 
tabella in ADMIN.
Ho ottenuto quello che volevo.
Un altro modo per ottenere questa cosa (di cancella/riscrivi) � per esempio:
creo un file dump da ADMIN con le istruzioni di DROP e CREATE TABLE.
Poi con un comando BATCH del tipo:
C:\"Program Files"\MySQL\"MySQL Server 5.0"\bin\mysql -uutente -pxxx 
<C:\Users\IO\Desktop\bat.sql
Nel file bat.sql � contenuta la stringa:
USE database_prova;
e il contenuto del file dump proveniente da ADMIN.
Questa soluzione del batch funziona solo sulla carta per� :(
Ho provato un file bat.sql piu semplice:
USE database_prova
select * from prodottilinee ORDER BY id  DESC;
e va tranquillamente. Immagino dunque che il problema stia nella
complessit� della query da eseguire.
Suggerimenti?
Franz

Ho ottenuto quello che volevo.
Um... avrei suggerito anch'io un replace completo, non fosse che tu prima
scrivevi:
	Se ho una tabella con il campo id che arriva a N e voglio
	importare un file (anch'esso con id che arriva a N) che mi fa
	una serie di insert proveniente da un altro DB, come faccio ad
	ignorare il campo ID e fargli "appendere" i nuovi record in coda
	a id = N?
e anche:
	Da considerare che le chiavi primarie delle tabelle dumpate
	nel file .sql non corrispondono ai valori che trovo nel DB
	di AGENTE, per cui bisognerebbe evitare una "sovrascrittura".
...come fai tu adesso, invece, usi proprio una sovrascrittura... e se il
DB di AGENTE e' un aggiornamento di ADMIN, com'e' possibile che vi possa
essere una "non corrispondenza ai valori"?
Dovresti avere
ADMIN	AGENTE
1	1
2	2
3	
4
ovvero AGENTE essere semplicemente un "po' indietro".


 ovvero AGENTE essere semplicemente un "po' indietro".
si, la cosa era iniziata cosi...
ADMIN   AGENTE
1	1
2	3
5	6
6	
7	
10
volevo che si "appendessero" le informazioni non presenti
e non volevo cancellare nulla.
Per� in realt�, la situazione schematizzata prima, era dovuta
a delle mie manipolazioni.
Nel caso reale, c'� corrispondenza tra gli id, per cui dovendo
la tabella di AGENTE essere una copia di quella
passata da ADMIN, allora ho optato per un replace da LOAD DATA.
Grazie per i tuoi preziosi suggerimenti.
Li user� per il caso contrario, ovvero quando AGENTE dovr�
popolare una tabella di ADMIN e in quel caso, si , NON c'�
corrispondenza.
E' una specie di sincronizzazione asincrona :)
Proprio come diceva Luigi.
Vado a pranzo che altrimenti svengo :)
Franz