Italian "INSERT multiple rows" via PHP

Elric

Well-Known Member
Licensed User
Partendo da qui: https://www.b4x.com/android/forum/threads/b4a-database-online.135571/post-861289, è possibile a vostro avviso fare un Insert multiplo? Qualcuno lo ha fatto? Se si, come?

Vorrei scartare il ciclo for di Insert singoli: se si tratta di 10 righe, non è un problema, ma 5000 potrebbero esserlo.

Allo stesso tempo, la sitassi per fare un Insert multiplo sarebbe:
SQL:
INSERT INTO
    projects(name, start_date, end_date)
VALUES
    ('AI for Marketing','2019-08-01','2019-12-31'),
    ('ML for Sales','2019-05-15','2019-11-20');
ma se formo una stringa composta di 5000 record con 10 campi, vuol dire più di 50000 parole per un comando via OkHttpUtils, cosa che non ho ancora provato.

Grazie!
 

Star-Dust

Expert
Licensed User
Longtime User
è possibile a vostro avviso fare un Insert multiplo?
Si
ma se formo una stringa composta di 5000 record con 10 campi, vuol dire più di 50000 parole per un comando via OkHttpUtils, cosa che non ho ancora provato.
Io non manderei 5000 campi in un solo insert. Alcune REST API (come quelle di DANEA) ti permettono di fare inserimento multipli (e letture multiple) per 10/20 record per volta. Questo è già molto perché riduci il carico di 10 volte.

Farlo di 5000 tutti insieme sarebbe una pazzia in qualunque linguaggio. In Angular il testo html creato per essere un buon codice deve rientrare in un limite massimo id caratteri. Anche quando fai download di dati (byte) non si scarica 1gigabyte di file in un invio ma viene spezzettato in piu trance.....

Quindi l'ide di un inserimento multiplo va bene, uno globale in una sola stringa non credo affatto
 
Upvote 0

Star-Dust

Expert
Licensed User
Longtime User
Mica posso rispondere a tutto io.

Comunque io manderei al php un JSON che contiene un array dei campi e dal php ricostruirei la query. Ma è solo un idea al volo, sicuramente potrebbero esserci idee migliori

Poi molti dipende da quale metodo usi nel php per passare i parametri
 
Upvote 0

Luciano Veneziano

Active Member
Licensed User
Longtime User
Io preferisco inviare i record uno a uno e verificare che l'acquisizione sia avvenuta correttamente.
Li mando in Post è funziona tutto bene.
 
Upvote 0

Elric

Well-Known Member
Licensed User
Nel frattempo che @Luciano Veneziano mi dica come fare, ho provato a darmi una risposta ma senza successo.

Allego progetto di test e qui di seguito una prima bozza di file php.

... che non funziona (tranne se il file json lo carico su server).

PHP:
<?php
    
    $table = ""; //Come la passo?

    echo "table = $table <br /><br />";
    echo "WOW! <br /><br />";

    $json = file_get_contents('php://input');
    //var_dump($json); // show contents
    //echo "<br />";
    //var_dump(count($json));
    //echo "<br />";
    
    $jsonIterator = new RecursiveIteratorIterator(
        new RecursiveArrayIterator(json_decode($json, TRUE)),
        RecursiveIteratorIterator::SELF_FIRST);
    
    $stackkey = [];
    $stackval = [];
    $ynStopKey = 0;
    foreach ($jsonIterator as $key => $val) {
        if(!is_array($val)) {
            if($ynStopKey == 0) {
                //print "key = ".$key."<br/>";
                //print "stackkey[0] = ".$stackkey[0]."<br/>";
                if($key == $stackkey[0]) {
                    //print "key = ".$key." & stackkey = ".$stackkey[0]."ynStopKey = 1<br/>";
                    $ynStopKey = 1;
                } else {
                    //print "key = ".$key." & stackkey = ".$stackkey[0]."ynStopKey = 0<br/>";
                    array_push($stackkey, $key);
                };
            };
          print $key."    : ".$val . "<br/>";
          array_push($stackval, $val);
        };
    };
    
    echo "<br />";
    for($i = 0, $size = count($stackkey); $i < $size; ++$i) {
      $sql = $sql . $stackkey[$i];
      if ($i < $size -1) {
        $sql = $sql . ", ";
      } else {
        $sql = $sql . " ";
      };
    };
    echo "key $sql";
    
    echo "<br />";
    echo "<br />";
    $sql = "";
    for($i = 0, $size = count($stackval); $i < $size; ++$i) {
      $sql = $sql . $stackval[$i];
      if ($i < $size -1) {
        $sql = $sql . ", ";
      } else {
        $sql = $sql . " ";
      };
    };
    echo "val $sql";
    
    echo "<br />";
    echo "<br />";
    $sql = ("INSERT INTO $table (");
    for($i = 0, $size = count($stackkey); $i < $size; ++$i) {
        $sql = $sql . $stackkey[$i];
        if ($i < $size - 1) {
          $sql = $sql . ", ";
        };
      };

    $sql = $sql . (") VALUES (");

    $stackkeysize = count($stackkey);
    for($i = 0, $stackvalsize = count($stackval); $i < $stackvalsize; ++$i) {
      $sql = $sql . $stackval[$i] . "'";
      if ($i < $stackvalsize - 1) {
        //print "i = ".$i." & stackkeysize = ".$stackkeysize." & (i % stackkeysize) = ".$i % $stackkeysize."<br/>";
        if ($i > 0 and ($i+1) % $stackkeysize == 0) {
            $sql = $sql . ("), (");
        } else {
            $sql = $sql . ", ";
        };
      } else {
        $sql = $sql . (")");
      };
    };
    echo "$sql";
    
?>

Qualcuno mi aiuta?

Con questo metodo, come passo il nome della tabella con cui poi costruire la query di insert?
 

Attachments

  • TestPostJSON.zip
    9.8 KB · Views: 171
Upvote 0

Luciano Veneziano

Active Member
Licensed User
Longtime User
E' facile. ho un unico file .PHP sul server (di fatto non uso alcuna pagina html) in cui mando la query come post
httpsPost("https:indirizzo","select * from navi where nome like ti%")
mi vengono restituite. se la query da un risultato
OK;3 'numero si records trovati
tianic;9;1890;
titanic;11;2010
tittis;45;2023
END
se faccio un'operazione di UPDATE o DELETE
OK;
END
In questo modo hai diverse opzioni, la più importante che non hai bisogno di drivers o files aggiuntivi e, soprattutto puoi creare applicazioni
concorrenti in piattaforme diverse, windows, linux, android os...
In ogni caso devi essere sicuro che la query abbia avuto successo, quindi se va storta una questi di 5000, come trovi dove sta il casino?
 
Last edited:
Upvote 0

Elric

Well-Known Member
Licensed User
Grazie Luciano Veneziano.

... ma non ho capito.

Il mio obiettivo è prendere dei dati in locale (da delle list o dal database SQLite locale) e fare un insert multiplo sul database in mySQL.

Nel primo post c'è un rinvio ad una precedente discussione. In questa precedente discussione, grazie alla guida @sirjo66, il metodo utilizzato è GET. Con questo si riesce a passare quasi tutto quello che mi serve: la stringa di query mySQL, il nome della tabella, i campi, i valori, i filtri etc.

GET, però, ha il limite di poco più di 2000 caratteri.

Quindi, superando i 2000 caratteri del link da utilizzare via GET, dovrei ricorrere a POST (poi ci sono le considerazioni sulla sicurezza sulle quali sorvolo).

Da quanto hai scritto capisco che mandi in POST la stringa di query (SQLite? mySQL?) ma poi? In che modo prendi dei dati in locale e riesci a fare un insert multiplo sul database in mySQL? La massa di dati la passi in json ma come indichi la stringa di query e la tabella?

Nella mia testa, dovrei riuscire ad inviare quantomeno il nome della tabella in cui fare l'insert e la massa di dati.

Su come passare il nome della tabella insieme alla massa di dati con POST ci sto lavorando (con scarso successo) e ogni suggerimento è ben accetto.

Per l'nvio della massa di dati, invece, non capisco se c'è un errore nel mio php, perché sembra funzionare.

Infatti, se il medesimo contenuto del json che invio in POST tramite app lo copio su un file json presente all'interno del server e sostituisco
B4X:
$json = file_get_contents('php://input');
con
B4X:
$json = file_get_contents(percorso+nome_file);
la pagina html del browser mi restituisce ciò che vorrei vedere e quindi il codice php funziona.

Ma lo stesso risultato non l'ottendo con l'invio a mezzo di app B4J. Questa riesce ad estrarre un json ma sembra non riuscire ad inviarlo, perché il file php restituisce delle stringhe di controllo tranne il contenuto del json.
 
Upvote 0

Luciano Veneziano

Active Member
Licensed User
Longtime User
provo oggi a fare delle prove. Ti dicevo che non uso fare insert multipli perché sono pericolosi e se qualcosa va storto ti trovi le tabelle compromesse.
Sul Post la sicurezza c'è se usi https.
click su guarda qui dove ti spiega il meccanismo di $json = file_get_contents('php://input');
 
Upvote 0

ivanomonti

Expert
Licensed User
Longtime User
rispondi anche al mio quesito che sto imbastardendo
 
Upvote 0

Luciano Veneziano

Active Member
Licensed User
Longtime User
 
Upvote 0

Luciano Veneziano

Active Member
Licensed User
Longtime User
Questo è il PHP

<?php
include_once("local/setup.php");

@$sql = $_POST["q"];

$mysqli = new mysqli("localhost",_USER,_PASS,_DATA);

if ($mysqli -> connect_errno) {
print $sql." - Errore di connessione MySQL";
exit();
}

if ($result = $mysqli -> query($sql)) {

print "OK;". mysqli_num_rows($result)."\r\n";

while($row = $result->fetch_assoc()) {
echo implode(';',$row);
print "\r\n";
}
}
$mysqli -> close();
print "END\r\n";
?>
 
Last edited:
Upvote 0

Luciano Veneziano

Active Member
Licensed User
Longtime User
Questo è il pezzo B4A

'-----------------------------------------------------------------------------------
Sub JobDone (Job As HttpJob)
End Sub
'-----------------------------------------------------------------------------------
Sub httpPost(path As String, SQL As String,id As String)
Dim j As HttpJob
j.Initialize("", Me)
j.PostString(path,SQL)
Wait For (j) JobDone(j As HttpJob)
If j.Success Then
refresh(id,j.GetString)
End If
j.Release
End Sub
'-----------------------------------------------------------------------------------
Sub refresh(id As String,res As String)
Select(id)
Case "fql": createFreqsList(res)
Case "usr": searchUser(res)
Case Else Log("errore:"&id)
End Select
End Sub
'-----------------------------------------------------------------------------------
Sub Post(sql As String,id As String)
httpPost("https://webhostapp.com/query.php","q="& sql,id)
End Sub
'-----------------------------------------------------------------------------------
Sub selUser(id As String)
Post("SELECT id, user, CF FROM users WHERE CF="&id,"usr")
End Sub
'-----------------------------------------------------------------------------------
Sub selFreqs(id As String)
CVF.Clear
Post("SELECT titolo,fsource.id,fid,uid,freq FROM fsource, fusers WHERE fsource.id = fusers.fid and uid = "&id&" group by fid","fql")
End Sub
 
Upvote 0

Elric

Well-Known Member
Licensed User
Grazie @Luciano Veneziano!

Grazie (1) per avermi dato un'intuizione:
Non funzionava perché l'URL da inserire è in "https" e non in "http". Una cosa stupida che avevo sottovalutato.

Nel mentre ho pensato che, dato che in POST passo una stringa, potrei manipolare la stringa nell'app (aggiungendo il comando di query e il nome della tabella) e poi manipolarla nuovamente in php ("splittando" la stringa e ricavando il comando, il nome della tabella e il json da cui recupero campi e valori).

Appena posso, aggiorno app e php.

Grazie (2) per avermi fornito il tuo metodo, che studierò!
 
Upvote 0

Luciano Veneziano

Active Member
Licensed User
Longtime User
Il mio metodo è stringato ed essenziale. funziona bene e sopratutto ti permette di creare la query in locale e "spararla" dall'altra parte.
Un altro vantaggio è, come ho già detto, che si possono creare applicazioni su diverse piattaforme che utilizzano il medesimo database senza alcun driver aggiuntivo.
Se hai dubbi fammi sapere.
P.S. preferisco usare i separatori piuttosto che JSON perché mi raddoppia le dimensione dei file da spedire dall'alttra parte.


Questo usa il sistema descritto con tre tabelle ed un'app windows, non ho il filmato dell'app android
 
Last edited:
Upvote 0

Luciano Veneziano

Active Member
Licensed User
Longtime User
Perdonami ma non capisco:
"e poi manipolarla nuovamente in php ("splittando" la stringa e ricavando il comando, il nome della tabella e il json da cui recupero campi e valori)."
Potresti spiegarmi il perché di tanta complicazione?
Al limite, se vuoi fare una cosa "spacchiosa" ti fai delle stored procedure.
 
Last edited:
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…