PDA

View Full Version : [PHP] Tabella dati ridondanti. Come eliminarli?


Gregor
02-10-2014, 13:05
Buongiorno,
ho una tabella con dei dati che stampo tranquillamente.
Sono tutti record unici e indipendenti, ma ogni tanto una riga è vincolata a quella immediatamente dopo avendo una parte di dati comuni e altri in più.
Quando stampo, stampo tutto, quindi in quei casi in cui ci sono rihhe dipendenti a due a due, ho una ridondanza di informazioni.
Il punto è che non ho trovato un modo per stampare solo la riga che contiene tutte le info (quelle comuni e quelle esclusive). avete una idea?

Grazie.

Gregor
06-10-2014, 15:39
Ecco un es.:


...
5- 01 8:00 I CASA 0
4- 01 7:50 I CASA 1
3- 01 7:50 I CASA 0
2- 01 7:45 I CASA 0
1- 01 7:30 I CASa 0
...

In pratica, le righe 3 e 4 dovrebbero essere unificate, perché è una ripetizione inutile!
Il punto è che una volta stampata la 3, solo dopo mi "accorgo" della 4 (è un array), cioè del fatto che sono due righe da unire! Solo che ormai la 3 è stampata in tabella e non riesco più a farci nulla!

Chiaro più o meno?

ndakota
06-10-2014, 20:05
Non si capisce molto dall'esempio in questione. Comunque, io penso che non puoi far dipende una riga dalla riga successiva, è una cosa che non ha senso. Puoi avere solo dati che dipendono da altri dati all'interno della riga stessa, al massimo. Probabilmente devi solo splittare quella tabella in due tabelle, ma non avendo capito l'esempio non riesco ad aiutarti più di così. Comunque credo sia un problema di design del database, non lo risolverei tramite PHP.

Gregor
06-10-2014, 20:31
Non ha senso? I dati sono quelli, non si scappa! Il mio approccio è sicuramente errato, perché una volta stampata una riga no posso fare più nulla a quei dati e quindi la riga dopo per forza è ridondante! Splittare le tabelle potrebbe essere una soluzione, ma non proprio semplice... I dati li leggo tramite php, perché il db si popola in un'altra fase.

Inviato da Huawei mobile

airon
07-10-2014, 09:01
Ciao,

scusa ma quale è il campo che ti permette di capire se aggregare o no? Intervieni sul quello durante il primo print...ti metti tutto in un array temporaneo e stampi poi quello se hai aggregato o meno...

Gregor
07-10-2014, 09:25
Ciao,

scusa ma quale è il campo che ti permette di capire se aggregare o no? Intervieni sul quello durante il primo print...ti metti tutto in un array temporaneo e stampi poi quello se hai aggregato o meno...

Il valore "1" dopo CASA nella riga 4.
Questo mi fa capire che la precedente (3) e la corrente (4) devono essere unite.

airon
07-10-2014, 11:25
Beh ma allora è più facile di come pensi:
leggi la prima riga dal DB e la metti in un array con due righe...leggi la seconda e la metti nell'array, confronti il valore 0 , 1. Se nella seconda riga del tuo array di stampa c'é 1 aggreghi se no stampi le due righe. Resetti l'array e continui così per tutti i record del DB.

ndakota
07-10-2014, 16:53
Secondo me è sbagliato risolvere da Php. Risolvi ma avrai della computazione in più per nulla, che se il db fosse a posto non avresti. Senza contare i dati ridondanti nel db appunto.

airon
07-10-2014, 22:30
Secondo me è sbagliato risolvere da Php. Risolvi ma avrai della computazione in più per nulla, che se il db fosse a posto non avresti. Senza contare i dati ridondanti nel db appunto.

Sicuramente è la strada da seguire...ma mi pare di avere capito che non vi è controllo su questo ;)

Gregor
08-10-2014, 06:44
Sicuramente è la strada da seguire...ma mi pare di avere capito che non vi è controllo su questo ;)

Esatto! I dati arrivano così nel DB.
Sicuramente si possono "lavorare" prima di popolare il DB, ma attualmente il flusso di dati non viene "sistemato" prima.

Daniels118
08-10-2014, 10:58
La situazione non mi è del tutto chiara, non potresti fare semplicemente una group by nella select?

Gregor
09-10-2014, 06:49
Dunque, la primaria è un ID che non utilizzo.
Vi è una chiave unica che raccoglie tutte le variabili (a parte ID, naturalmente)...questo per evitare di memorizzare records doppi che possono passare...Tabella unica, non legata ad altre.

Ho capito che non devo stampare ad ogni iterazione dell'array, ma appunto "memorizzare" per poi controllare le righe accoppiate, fare le dovute sistemazioni e poi stampare.
Però è più facile a dirsi che a farsi...:stordita:

MicheleRaponi
09-10-2014, 08:17
Ecco un es.:


...
5- 01 8:00 I CASA 0
4- 01 7:50 I CASA 1
3- 01 7:50 I CASA 0
2- 01 7:45 I CASA 0
1- 01 7:30 I CASa 0
...

In pratica, le righe 3 e 4 dovrebbero essere unificate, perché è una ripetizione inutile!
Il punto è che una volta stampata la 3, solo dopo mi "accorgo" della 4 (è un array), cioè del fatto che sono due righe da unire! Solo che ormai la 3 è stampata in tabella e non riesco più a farci nulla!

Chiaro più o meno?

Non è molto chiaro cosa intendi con "unificare"..dicendo "é una ripetizione inutile" credo che il valore 1 indichi che la riga che lo possiede abbia sempre contenuto identico alla precedente con valore 0 ( a meno dell'ultimo campo, quello che può avere valore 0 o 1).
Se si, puoi agire così ed eliminare quella con valore 0 e mantenere quella con valore 1:

http://viper-7.com/R7lEgd

Gregor
09-10-2014, 08:21
Non è molto chiaro cosa intendi con "unificare"..dicendo "é una ripetizione inutile" credo che il valore 1 indichi che la riga che lo possiede abbia sempre contenuto identico alla precedente con valore 0 ( a meno dell'ultimo campo, quello che può avere valore 0 o 1).
Se si, puoi agire così ed eliminare quella con valore 0 e mantenere quella con valore 1:

http://viper-7.com/R7lEgd

Esatto! "unificare" vuol dire stampare solo la 4- e non anche la 3-
Guardo il tuo esempio. Grazie.

Ho visto...se però la base di partenza è

$rows[7] = array('01','8:50','I','CASA','1');
$rows[6] = array('01','8:50','I','CASA','0');
$rows[5] = array('01','8:00','I','CASA','0');
$rows[4] = array('01','7:50','I','CASA','1');
$rows[3] = array('01','7:50','I','CASA','0');
$rows[2] = array('01','7:45','I','CASA','0');
$rows[1] = array('01','7:30','I','CASA','0');

Il risultato è

7) 01 | 8:50 | I | CASA | 1 |
6) 01 | 8:50 | I | CASA | 0 |
5) 01 | 8:00 | I | CASA | 0 |
4) 01 | 7:50 | I | CASA | 1 |
2) 01 | 7:45 | I | CASA | 0 |
1) 01 | 7:30 | I | CASA | 0 |

e chiaramente non va bene...

Posso avere n righe da "unificare"...tenendo sempre quella col valore $v[4] == 1.

airon
09-10-2014, 10:29
Se vuoi unificare via php devi stampare a due a due...come ti ho detto di fare io ;)

Hai bisogno di un array temporaneo di stampa.
Metti dentro una riga (0), metti dentro la seconda (0). Le stampi.
Resetti l'array.
Metti dentro una riga (0), metti dentro la seconda (1). Aggreghi e stampi.
Resetti
ecc.

MicheleRaponi
09-10-2014, 11:00
Esatto! "unificare" vuol dire stampare solo la 4- e non anche la 3-

Posso avere n righe da "unificare"...tenendo sempre quella col valore $v[4] == 1.

Allore devi avere un array con le chiavi da rimuovere e non una variabile, poi devi avere un ciclo per rimuvovere dall'array secondo le chiavi che ti ricavi.

http://viper-7.com/lGGkGb

ndakota
09-10-2014, 13:36
Ma scusa, se a te interessa che quelle con 1 finale sovrascrivano 0 finale, anziché salvare entrambe le righe nel db, non puoi andare in update sulla riga e salvare 1? Così ti estrai le righe giuste e in Php non devi fare nulla. E non hai neanche duplicati sul db.

Gregor
14-10-2014, 05:33
Le righe doppie mi servono in altri ambiti e quindi nel db devono restare. Una select che per le righe "doppie" prende solo quelle con valore 1 ci può stare. Forse una select concatenata... Devo prenderle tutte le altre. Le altre soluzioni mi sembrano complicate...

Inviato da Huawei mobile con Tapatalk

Gregor
14-10-2014, 08:15
Sto seguendo la strada di @MicheleRaponi che mi sembra semplice per le mie conoscenze di php.
Questa la partenza; il mio array nasce così:

Stampo tutte le righe:

$query = "select...";
$dbResult = mysql_query($query, $db);
$AffectedRows= mysql_affected_rows($db);

for ($index=0 ; $index<$AffectedRows ; $index++)
{
$row = mysql_fetch_row($dbResult);
foreach ($row as $k => $v)
{
print ($v);
}
}


Edit: credo di essere a buon punto!
Ho un array con le righe da non stampare...

Array
(
[0] => 2
[1] => 5
[2] => 10
[3] => 12
)

adesso devo "semplicemente" escluderle nel ciclo for...cioè $index non deve avere quei valori...

for ($index=0 ; $index<$AffectedRows ; $index++)
...

Gregor
14-10-2014, 10:01
Non ci sono ancora!

print "<table>\n";

for ($index=0 ; $index<$AffectedRows ; $index++)
{
$row = mysql_fetch_row($dbResult);
print "<tr>\n";

foreach ($row as $k => $v)
{
if($k == 4)
{
if($v == 3)
{
$keys_to_remove[] = $index-1;
}
}
print ("<td><div align=\"center\">$v</div> </td>\n");
// In realtà non mi serve stampare in questo for...
}
print "</tr>\n";
}
print("</table>\n");


Così stampo la tabella completa e in più ho l'array $keys_to_remove[] che contiene il numero di righe da non stampare!
Partendo dalla prima (0) all'ultima, ho il numero esatto di ciò che non mi serve!
Adesso devo ripartire da un for analogo, dove stamperò tutte le righe da 0 ad $AffectedRows ad eccezione di quelle nell'array precedente...

LS1987
14-10-2014, 11:07
La situazione non mi è del tutto chiara, non potresti fare semplicemente una group by nella select?

Concordo.

Gregor
14-10-2014, 11:50
Concordo.

Sto provando anche questa strada, apparentemente più semplice...e ho trovato il modo di non stampare righe doppie, solo che mi esclude quelle con valore 1 nel campo di riferimento e quindi non va bene!

Cioè dal totale:

originale
10) 01 | 8:50 | I | CASA | 1 |
9) 01 | 8:50 | I | CASA | 0 |
8) 01 | 8:30 | I | CASA | 0 |
7) 01 | 8:50 | I | CASA | 1 |
6) 01 | 8:50 | I | CASA | 0 |
5) 01 | 8:00 | I | CASA | 0 |
4) 01 | 7:50 | I | CASA | 1 |

Raggruppando ottengo:

originale
9) 01 | 8:50 | I | CASA | 0 |
8) 01 | 8:30 | I | CASA | 0 |
6) 01 | 8:50 | I | CASA | 0 |
5) 01 | 8:00 | I | CASA | 0 |
4) 01 | 7:50 | I | CASA | 1 |

Io vorrei tenere, per le righe "doppie", quelle che hanno valore 1 (nell'es., in ultima colonna).

Gregor
14-10-2014, 18:15
adesso quindi dovresti fare un for che stampi solo le righe che non hanno indice compreso dentro l'array degli indici da scartare, e che abbia l'ultimo campo a 1
Mi sono un po' arenato su questa strada... Sono stato tutto il giorno sul codice...e non ho avuto l'ispirazione. Ho provato anche la strada Group by... ma vengono eliminate d'ufficio i records sbagliati. Insomma, al momento lascio la stampa ridondante...

Inviato da Huawei mobile con Tapatalk

Gregor
15-10-2014, 12:03
Tabella unica! Semplice semplice. ID è la key che non uso e poi chiave unica che coinvolge determinati campi per evitare in fase di popolamento records duplicati.

Si popola e poi leggo tramite php le righe e le stampo.

Sono arrivato qui:


$query = "select ..... ";

$dbResult = mysql_query($query, $db);
$AffectedRows= mysql_affected_rows($db);


print "<table>\n";

for ($index=0 ; $index<$AffectedRows ; $index++)
{
$row = mysql_fetch_row($dbResult);
print "<tr>\n";

foreach ($row as $k => $v)
{
if($k == 4)
{
if($v == 3)
{
$keys_to_remove[] = $index-1;
}
}
print ("<td><div align=\"center\">$v</div></td>\n");
}

print "</tr>\n";
}
print("</table>\n");



Così printo la tabella completa e nell'array $keys_to_remove ho gli indici ($index) che devo scartare.

Ovviamente il codice precedente lo ripulisco per bene, perchè non mi serve stampare la tabella completa.

Lo riprenderò dopo aver inserito le condizioni per escludere dal for gli indici che ho già trovato...

Ho provato in un altro ciclo for a inserire condizioni su $index, che mi facessero escludere gli indici dell'array $keys_to_remove, ma non ho prodotto nulla di valido!

Gregor
15-10-2014, 13:18
Allora in un altro for riscorrerai riga per riga l'estrazione precedente, non stampando le righe con gli indici nell'array dove hai quelli da saltare.

Mi sembra che poi sia finito.

Esatto! In teoria è tutto lì, ma qualcosa non ha funzionato. Appena riesco riprendo in mano il codice e posto le modifiche, magari salta fuori l'errore.
Tnx!

Edit: forse ho trovato l'errore!
Il $row = mysql_fetch_row($dbResult); andava inserito prima della condizione if($index...) e non dopo!
Ecco perchè non mi tornavano le righe filtrate nel ciclo for....

Sistemo, metto a posto il codice e poi lo posto :D

Gregor
15-10-2014, 13:35
Adesso dovrebbe essere a posto:


<?php
$query = "select ...";
$dbResult = mysql_query($query, $db);
$AffectedRows= mysql_affected_rows($db);

//Cerco i record da non stampare e creo l'array $keys_to_remove

for ($index=0 ; $index<$AffectedRows ; $index++)
{
$row = mysql_fetch_row($dbResult);
foreach ($row as $k => $v)
{
if($k == 4)
{
if($v == 3)
{
$keys_to_remove[] = $index-1;
}
}
}
}


$dbResult = mysql_query($query, $db);
$AffectedRows= mysql_affected_rows($db);

// Tabella
print "<table>";
for ($index=0 ; $index<$AffectedRows ; $index++)
{
$row = mysql_fetch_row($dbResult);
if(!in_array($index, $keys_to_remove))
{
print "<tr>\n";
foreach ($row as $k => $v)
{
print ("<td>$v</td>\n");
}
print "</tr>\n";
}
}
print("</table>\n");
mysql_close($db);
?>


Che dite?

Sapete perchè devo ripetere le istruzioni:
$dbResult = mysql_query($query, $db);
$AffectedRows= mysql_affected_rows($db);

Se le ometto, la query non va a buon fine...:mbe:

Grazie :D

Gregor
15-10-2014, 14:40
Problema: se escludo anche solo un valore, tutto ok!
Ma se non ci sono valori da escludere (e devo valutare anche questo caso), ottengo:

Warning: in_array() [function.in-array]: Wrong datatype for second argument in

Però la tabella la stampa!

Non mi piace nascondere i warning, sapete come rimediare? Tnx!

Al momento riscrivo il codice dopo if(!in_array($index, $keys_to_remove)) senza lanciare questa istruzione, verificando se l'array è pieno o vuoto, ma è un ripetizione di codice che non mi piace...

LS1987
15-10-2014, 16:30
Problema: se escludo anche solo un valore, tutto ok!
Ma se non ci sono valori da escludere (e devo valutare anche questo caso), ottengo:

Warning: in_array() [function.in-array]: Wrong datatype for second argument in

Però la tabella la stampa!

Non mi piace nascondere i warning, sapete come rimediare? Tnx!

Al momento riscrivo il codice dopo if(!in_array($index, $keys_to_remove)) senza lanciare questa istruzione, verificando se l'array è pieno o vuoto, ma è un ripetizione di codice che non mi piace...

Se è codice lato server ripetilo pure, tanto il client non se ne accorge.

Gregor
15-10-2014, 17:01
Si certo non se ne accorge, ma una soluzione più fine ci sarà... Anche perché non è il max vedere ripetersi lo stesso codice o quasi...

Inviato da Huawei mobile con Tapatalk

Daniels118
15-10-2014, 17:47
Il problema è che $keys_to_remove non è inizializzato, devi aggiungere
$keys_to_remove = array();
prima del primo for.

Gregor
15-10-2014, 19:57
Il problema è che $keys_to_remove non è inizializzato, devi aggiungere
$keys_to_remove = array();
prima del primo for.
Sapevo che non era necessario inizializzarlo... Cosa cambia? Grazie. P.S. così funziona.

Inviato da Huawei mobile con Tapatalk

LS1987
15-10-2014, 20:32
Sto provando anche questa strada, apparentemente più semplice...e ho trovato il modo di non stampare righe doppie, solo che mi esclude quelle con valore 1 nel campo di riferimento e quindi non va bene!

Cioè dal totale:

originale
10) 01 | 8:50 | I | CASA | 1 |
9) 01 | 8:50 | I | CASA | 0 |
8) 01 | 8:30 | I | CASA | 0 |
7) 01 | 8:50 | I | CASA | 1 |
6) 01 | 8:50 | I | CASA | 0 |
5) 01 | 8:00 | I | CASA | 0 |
4) 01 | 7:50 | I | CASA | 1 |

Raggruppando ottengo:

originale
9) 01 | 8:50 | I | CASA | 0 |
8) 01 | 8:30 | I | CASA | 0 |
6) 01 | 8:50 | I | CASA | 0 |
5) 01 | 8:00 | I | CASA | 0 |
4) 01 | 7:50 | I | CASA | 1 |

Io vorrei tenere, per le righe "doppie", quelle che hanno valore 1 (nell'es., in ultima colonna).

Vorresti stampare la riga 7 o la riga 10)? Hai provato ad utilizzare la clausola DISTINCT al posto del group by? Oppure puoi raggruppare su tutti i campi, non so se queste due opzioni ti potrebbero creare problemi altrove.

Gregor
15-10-2014, 20:38
7 e 10 al posto di 6 e 9. Con un semplice Group by ottengo però le righe 7 e 10. Ho provato in vari modi, ma il Group by non credo risolva da solo.

Inviato da Huawei mobile con Tapatalk

Daniels118
16-10-2014, 08:11
Sapevo che non era necessario inizializzarlo... Cosa cambia? Grazie. P.S. così funziona.

Inviato da Huawei mobile con Tapatalk
In PHP non è necessario dichiarare le variabili, per cui l'istruzione
$array[] = $valore;
crea l'array se non esiste già.
Tuttavia se l'istruzione non viene mai eseguita, la variabile $array non contiene un array e viene interpretata come "non definita", di conseguenza la funzione in_array (che si aspetta un array) ti avvisa: "Wrong datatype for second argument".

Gregor
16-10-2014, 12:07
In PHP non è necessario dichiarare le variabili, per cui l'istruzione
$array[] = $valore;
crea l'array se non esiste già.
Tuttavia se l'istruzione non viene mai eseguita, la variabile $array non contiene un array e viene interpretata come "non definita", di conseguenza la funzione in_array (che si aspetta un array) ti avvisa: "Wrong datatype for second argument".

Ah ok, ho capito.
Adesso provo. Tnx! :D

Naturalmente funziona!
Ho potuto così "pulire" un pò il codice. Grazie ;)

Gregor
16-10-2014, 16:02
Effettivamente sono anni che programmo così, spero un giorno non dover scoprire che è codice non più funzionante. Il bignami php4 della hoepli è stato inizio e fine della mia formazione :(

Inviato da Huawei mobile con Tapatalk

Daniels118
17-10-2014, 19:17
Il fatto che le vecchie funzioni potrebbero non essere presenti nelle nuove versioni non significa che ciò che è stato fatto fino ad oggi non funzionerà più, basta lasciarlo sulle vecchie piattaforme.
Se invece si comincia a sviluppare qualcosa di nuovo è meglio adeguarsi da subito.