[python] Semplice esercizio su TensorFlow e il riconoscimento delle immagini nel gioco del Tris (Machine Learning)

Vogliamo realizzare un semplice programma in Python che sfrutti il riconoscimento delle immagini mediante TensorFlow e machine learning.

Il programma consentirà all’utente di pescare il risultato di una partita a Tris, da una cartella di immagini come la seguente:

Selezionando una partita il programma ci dirà chi ritiene che sia il vincitore e mostrerà lo schema della partita che ha dedotto a partire dall’immagine che gli abbiamo passato, nella maniera seguente:

1. Configurazione iniziale e librerie utilizzate

Per affrontare l’esercizio in questione abbiamo bisogno di alcune librerie. Il progetto verrà sviluppato in Python 3.7.

Possiamo installare le opportune librerie utilizzando PIP, nel caso specifico avremo bisogno delle seguenti installazioni:

Creiamo un file elaboratore.py nel quale svilupperemo l’intero programma. All’inizio inseriamo le seguenti istruzioni di importazione:

Faccio notare che la prima istruzione from __future__ import absolute_import, division, print_function, unicode_literals deve trovarsi all’inizio e non è una vera e propria importazione. Si tratta di una configurazione sul funzionamento di Python, che importa “funzionalità future” dal modulo fittizio __future__. E’ un modo per rendere disponibili, nella versione attuale, funzionalità previste in versioni successive, ma che ancora non sono state ufficialmente implementate.

Nel nostro caso specifico questa importazione non è essenziale (stiamo già lavorando in Python 3.7 e la funzione print non è più uno statement, bensì una funzione appunto, ecc), ma la possiamo lasciare per rendere compatibile il programma anche con versioni precedenti.

Detto questo procediamo allo sviluppo del necessario.

2. Dati iniziali

Per sviluppare il gioco utilizzeremo i seguenti set di dati (qui l’allegato da cui scaricarli):

  1. Set delle immagini per l’addestramento del modello, ricaveremo le immagini da un’unica grande immagine originale chiamata training.jpg (questa è un’immagine contenente 144 disegni, metà sono O e l’altra metà sono X, disegnate a mano sul computer, ciascun elemento è grande 100×100 px, per un totale di 1200×1200 px, ovvero 12 righe x 12 colonne)

  2. Piccolo set di immagini di test nel file test.jpg (solita dimensione 100×100 px per ciascuna immagine, per un totale di 4×4 = 16 elementi)
  3. Archivio con 10 partite giocate a Tris di cui conosciamo il risultato e vogliamo farlo riconoscere al computer

3. Struttura del programma

Vogliamo creare 3 classi che si occuperanno di diversi aspetti del programma:

  1. ElaboraImmagini – con questa classe elaboreremo le immagini di test, di addestramento e delle singole partite. In tutti e tre i casi si tratta di suddividere un’immagine originale in immagini più piccole; nei primi due casi, quello di test e addestramento, salveremo le immagini in una cartella da cui leggerle successivamente, mentre nel terzo caso, quello delle immagini che compongono una partita, salveremo il risultato in un vettore
  2. CreaDBImmagini – con questa classe vogliamo elaborare le immagini di test e di addestramento salvate nelle rispettive cartelle, ottenendo dei vettori contenenti le immagini medesime e un elenco di output (o etichette) associati a ciascuna immagine
  3. GiocoTris – la vera e propria classe che si occuperà dello sviluppo del gioco, preparando il modello di apprendimento, salvandolo e valutando il punteggio su ciascuna partita che verrà passata dal giocatore

Infine metteremo tutto in un semplice ciclo while che permetterà all’utente di scegliere un’immagine dall’elenco di quelle disponibili e farla analizzare.

4. Elaboriamo le immagini di addestramento e test

Creiamo una classe nella maniera seguente (nel codice ho inserito il commento sui singoli passaggi):

Il metodo ritaglia(s, coor, i) accetta coordinate in (x,y) sull’immagine, le x rappresentano le “colonne”, mentre le y rappresentano le “righe”, nella maniera seguente:

La prima immagine verrà ritagliata con coordinate (0, 0, 100, 100), la seconda con (100, 0, 200, 100) ecc.

Possiamo subito elaborare le immagini di addestramento e di test aggiungendo le seguenti due righe di codice:

5. Preleviamo le immagini di addestramento e test, associandoci gli opportuni output

Adesso vogliamo creare la classe che ci consentirà di prelevare le immagini, inserendole in un vettore, ed associare a ciascuna immagine nel vettore l’opportuno output.

Ogni immagine può rappresentare o una O oppure un X, a queste due “etichette” vogliamo associare un valore numerico, che nel mio caso sarà 0 per la O e 1 per la X.

Il comportamento che ci aspettiamo sarà il seguente: train_img, train_desc = CreaDBImmagini(...).get()

train_img conterrà i valori RGB per ciascuna immagine, in una lista di immagini così codificate. Ciascuna immagine è una griglia di pixel, per esempio un’immagine di 3×3 px diventerebbe una matrice di questo tipo [[1,2,3],[4,5,6],[7,8,9]]. I pixel in realtà non sono numerati in questo modo, ma ciascun pixel ha un valore RGB da 0 a 255, per ciascun colore. Quindi se il primo pixel fosse completamente nero al posto dell’1 avremmo [0,0,0], una lista con 3 zeri. Se fosse completamente bianco avremmo [255,255,255], se fosse rosso avremmo [255,0,0] ecc. Questo significa che l’immagine del nostro esempio avrebbe una rappresentazione tridimensionale 3x3x3 diventando così per esempio: [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[255,255,255],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]]. In questo caso il pixel centrale, quello che abbiamo numerato come 5, sarebbe bianco e gli altri tutti neri. Se avessimo 100 di queste immagini, avremmo un oggetto di dimensione 100x3x3x3. Ovvero una lista di 100 elementi, di cui ciascun elemento è questa lista, di liste di liste, rappresentante la singola immagine.

train_desc è invece una semplice lista monodimensionale, se avessimo 100 immagini questa sarebbe una lista di 100 elementi. Ogni elemento descrive l’immagine, nel nostro caso se l’immagine corrispondente in train_img fosse una O allora avremo uno 0, nel caso di una X avremo un 1. Sarà quindi una lista tipo [0,1,1,0,0,....]. In questo esempio vorrebbe dire che le immagini in train_img rappresentano in ordine: O, X, X, O, O, ecc.

Tutti gli altri commenti sono nel codice:

6. Sviluppiamo la classe di gioco

A questo punto sviluppiamo la classe di gioco integrando le precedenti classi.

Anche su questo facciamo un paio di appunti. Quando calcoliamo le previsioni con previsione = s.__modello.predict(gioco) otteniamo una lista di liste di probabilità. Ogni sub-lista contiene tante probabilità quanti sono i neuroni (o nodi) impostati nell’ultimo layer del modello. Nel nostro caso all’istruzione keras.layers.Dense(2, activation='softmax') abbiamo impostato 2 neuroni, quindi il vettore di previsione conterrà un elenco di liste del tipo [p1, p2], dove p1 e p2 sono le probabilità dell’output 0 e dell’output 1 (che ricordiamoci corrispondono a O e a X, rispettivamente). Il risultato di previsione sarà qualcosa del tipo [[1. 0.],[0.51 0.49], [0. 1.]]. Nel caso specifico vorrebbe dire che secondo il ML la prima immagina è una O, poi uno spazio vuoto, poi una X. Per quanto riguarda l’uso di softmax e relu fare riferimento a questa pagina.

Per i dettagli sull’optimizer Adam fare riferimento a questa pagina.

Il calcolo della griglia di vittoria è molto semplice, perché abbiamo un vettore lineare e non una matrice (o griglia vera e propria). In questo caso una partita come quella del gioco_1.jpg sarà rappresentata da una lista di 0, 1 e 2, in questo modo (dove 0 = vuoto, 1 = O, 2 = X): [2, 2, 1, 2, 1, 0, 2, 1, 1]

Quando il primo valore è diverso da 0, quindi da vuoto, basta controllare che a distanza di 3 siano uguali, come qui: [2, 2, 1, 2, 1, 0, 2, 1, 1]

In questo modo stiamo controllando le colonne.

Per controllare le righe basta verificare le triplette, così: [2, 2, 1, 2, 1, 0, 2, 1, 1]

7. Chiudiamo il programma

Infine costruiamo il ciclo while per poter far usare il programma:

Per completezza riporto di seguito l’intero codice di programmazione:

 

[python] Esercizio su funzioni ricorsive e calcolo del percorso minore possibile

Immaginiamo di avere la seguente situazione: su una griglia rettangolare abbiamo due punti, A e B e vogliamo calcolare il minore percorso possibile per arrivare da A a B, evitando degli ostacoli. Da una cella all’altra ci si può spostare solamente in verticale ed orizzontale.

Possiamo schematizzare il problema in qualcosa di simile.

Anzitutto impostiamo le variabili necessarie:

In particolare faccio notare che terremo tutti i percorsi in una lista percorsi = [] e vogliamo anche tenere traccia della minima lunghezza trovata con minlen. Questo accorgimento, come vedremo successivamente, ci servirà per ridurre notevolmente la quantità di calcoli da dover effettuare, eliminando tutti i percorsi che via via dovessero rivelarsi più lunghi del minimo percorso trovato (fino a quel momento).

A questo punto generiamo la matrice del mondo:

Adesso scriviamo la funzione per popolare il mondo di blocchi, le X del disegno precedente. Per farlo utilizzeremo la libreria random, per cui ricordiamoci di importarla all’inizio con import random

Utilizziamo random.randint per generare una posizione casuale su righe e colonne per i blocchi, verifichiamo che tale punto non sia già occupato da un blocco, in tal caso procediamo ad aggiungerlo.

In modo analogo creiamo un metodo che aggiunga la posizione iniziale A e quella finale B, registrandole nelle rispettive variabili.

Per trovare il percorso procediamo nella maniera seguente:

Faccio notare una peculiarità, legata al modo in cui Python tratta le liste. Per passare il percorso attuale, copiandolo, alla funzione medesima, dobbiamo usare un piccolo trucco scrivendo []+percorso. In questo modo evitiamo che il percorso sia passato per riferimento, forzando il programma a crearne una copia.

Fatto tutto questo aggiungiamo un metodo per la stampa della matrice:

E un metodo per prendere uno dei percorsi più corti calcolati (ricordiamoci che potrebbero esserci più percorsi):

Infine uniamo tutto quanto insieme, importando anche la libreria temporale con import time per valutare la velocità di elaborazione.

Di seguito il codice completo:

L’output finale darà qualcosa di simile a questo:

[prestashop] Expression #11 of SELECT list is not in GROUP BY clause and contains nonaggregated column

Problema: dopo un cambio di database (senza alcuna modifica al dominio) in Prestashop non vengono più visualizzati i prodotti nelle singole categorie e accedendo al pannello di controllo si presenta un errore del tipo Expression #11 of SELECT list is not in GROUP BY clause and contains nonaggregated column [...] which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

Soluzione: Modificare l’opzione sql_mode in sql_mode='STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION'

Nel caso specifico sarebbe sufficiente modificare la variabile globale sql_mode eseguendo la query:

Purtroppo questa modifica, che sarebbe quella ottimale e definitiva, non è sempre possibile da attuare a causa dei permessi sul database. Nel caso in cui non la si possa mettere in pratica sarà sufficiente modificare il file classes/db/DbPDO.php nella maniera seguente.

Aprendo il file alla riga 63 si troverà la seguente funzione:

Modificare la funzione nella maniera seguente, aggiungendo prima di return il pezzo di codice evidenziato:

Questa soluzione è stata presa da questo commento nel forum ufficiale.

[dax] Creare una tabella temporanea con SUMMARIZE ed effettuarci sopra dei calcoli

In questo esempio utilizzerò i dati già usati per: Analizzare i dati da Excel e MySQL utilizzando Power BI (per esordienti totali)

Quello che vogliamo fare è calcolare, nella tabella agenti, la media delle vendite di tutti gli altri agenti eccetto quello corrente ed utilizzarla come obiettivo KPI.

Anzitutto vediamo come è composta la tabella vendite usando la seguente query:

I dati che avremo saranno i seguenti:

Ricordiamoci che nel nostro esempio la tabella agenti ha “solo” 6 agenti, fino all’id 6.

Se adesso volessimo calcolare, in SQL, la media delle vendite di tutti gli agenti, escluso quello corrente, per ciascun agente, dovremmo eseguire una query come la seguente:

Questo ci darebbe un risultato simile al seguente:

Per ottenere lo stesso risultato in DAX dovremmo creare una tabella temporanea delle vendite e poi effettuare su di essa il calcolo della media, nel modo seguente:

La tabella provvisoria fa le veci della prima query, sulla quale poi eseguiamo il calcolo con AVERAGEX.

Analizzare i dati da Excel e MySQL utilizzando Power BI (per esordienti totali)

Procuriamoci anzitutto il necessario per poter lavorare, in questo esempio utilizzerò un database MySQL, un file Excel con ulteriori dati da integrare e Power BI.

In ordine avremo quindi bisogno di:

  1. XAMPP per server MySQL e PHPMyAdmin (non è necessario utilizzare XAMPP, si può usare un qualunque database MySQL ovviamente)
  2. Un database con dei dati di esempio che puoi scaricare da qui (questo database è già stato utilizzato nell’esercizio [mysql] Creare tabella pivot dinamica in MySQL (per esordienti totali))
  3. Un file excel con integrazioni dei dati per clienti e agenti che puoi scaricare da qui
  4. Power BI che possiamo ottenere gratuitamente a questo link
  5. MySQL Connector/NET 8.0.20 che si può scaricare da questo link (se non lo installiamo in anticipo sarà Power BI stesso ad invitarci di farlo nel momento in cui vorremo collegare un database MySQL)

Preparato tutto questo possiamo cominciare a lavorare con Power BI.

1. Importazione dati da MySQL

Avviamo Power BI e scegliamo Recupera dati dalla maschera iniziale.

Nel campo di ricerca cerchiamo mysql:

Selezioniamo il database MySQL. Se non abbiamo installato il connettore, come indicato prima, ci verrà chiesta l’installazione. In caso contrario procediamo configurando il database. Inseriamo, se stiamo usando XAMPP, come server 127.0.0.1 e il nome del database, nel mio caso powerbi.

Procediamo premendo OK ed impostiamo nome utente del database come root e lasciamo il campo password vuoto.

All’avviso sul supporto crittografia premiamo OK.

A questo punto selezioniamo tutte le tabelle che intendiamo caricare. Nel caso specifico selezioneremo tutte le tabelle eccetto storico_vendite.

Premiamo sul tasto carica.

2. Elaborazione dati

A questo punto elaboriamo le connessioni tra le tabelle. Sulla sinistra spostiamoci su modello:

Dovremmo vedere qualcosa di simile a questo.

Spostandoci su una qualsiasi delle relazioni notiamo come siano stati associati automaticamente gli ID. Purtroppo queste associazioni non vanno bene, perché i nomi delle colonne, tra le varie tabelle non corrispondono. A vendite.idAgente corrisponde infatti agenti.id, mentre secondo il sistema automatico vendite.id corrisponde a agenti.id. Possiamo ricostruire le associazioni trascinando i campi gli uni sugli altri, oppure andando ad intervenire da Gestisci relazioni, nella scheda Home > Relazioni.

Cliccando su Gestisci relazioni si aprirà una schermata come la seguente:

Modifichiamo opportunamente tutte le relazioni. Per esempio quella tra vendite ed agenti nel modo seguente:

Se abbiamo fatto tutto correttamente dovremmo vedere qualcosa di simile a questo:

Faccio notare che in tutti i casi ho impostato direzione filtro incrociato su Entrambi. L’utilizzo dell’opzione è finalizzato specificatamente alla semplificazione dell’uso dei filtri. La stessa Microsoft lo spiega nell’articolo Abilitare il filtro incrociato bidirezionale con DirectQuery in Power BI Desktop

Con il filtro incrociato bidirezionale, gli autori di report e modelli di dati hanno ora un maggiore controllo sulla modalità di applicazione dei filtri durante l’uso di tabelle correlate. Il filtro incrociato bidirezionale consente loro di applicare filtri su entrambi i lati di una relazione tra tabelle. Per ottenere questo risultato, il contesto di filtro viene propagato a una seconda tabella correlata sull’altro lato della relazione.

Fatto tutto questo lo schema che visualizzeremo sarà come il seguente:

3. Creiamo la nostra prima tabella nel report

Adesso mettiamo alla prova il sistema creato e proviamo a visualizzare il totale venduto dagli agenti.

Modifichiamo anzitutto il nome della pagina in Vendite:

Dalle visualizzazioni selezioniamo Tabella:

Poi afferriamo il nome dell’agente e trasciniamolo nella tabella. Stessa cosa per importo dalla tabella vendite:

Vedremo un risultato simile a questo:

Questo succede perché nelle vendite c’è un idAgente che non corrisponde ad alcun agente nella tabella agenti. Quello che vorremmo ottenere è una tabella di agenti LEFT JOIN vendite. Per farlo andiamo su Query e clicchiamo su Trasforma dati.

Clicchiamo col destro nel riquadro Query e selezioniamo Nuova query > Combina > Unisci query come nuova:

Configuriamo una LEFT OUTER JOIN nella maniera seguente:

A questo punto vedremo una tabella come la seguente:

Noi vogliamo visualizzare i dati aggregati delle vendite, quindi clicchiamo sul pulsante in alto a destra di powerbi vendite.

Selezioniamo l’opzione di aggregazione nella maniera seguente, scegliendo quantità e importo.

Dovremmo ottenere qualcosa di simile a questo:

Sulla destra clicchiamo sulla nuova tabella col destro e rinominiamola in vendite_x_agente. A titolo di esempio vogliamo anche aggiungere una colonna che calcoli l’importo medio di vendita per quantità di venduto.

Creiamo la colonna nella maniera seguente:

La formula che usiamo è: = Table.AddColumn(#"Colonne powerbi vendite aggregate", "media", each [Somma di powerbi vendite.importo] / [Somma di powerbi vendite.qta])

Fatto tutto questo salviamo e scegliamo di applicare i dati dal prompt che ci apparirà sullo schermo. Chiudiamo e torniamo a Power BI.

Sotto la voce Campi clicchiamo col destro su vendite_x_agente e aggiungiamo un’altra colonna (lo potevamo fare anche prima, ma per esercizio voglio farlo da questa posizione diversa): Nel campo formula digitiamo: nominativo = vendite_x_agente[nome]& " " & vendite_x_agente[cognome]

In questo modo abbiamo concatenato il nome e il cognome di ciascun agente aggiungendo in mezzo uno spazio.

A questo punto rinominiamo le colonne aggiunte prima, in modo da ottenere la seguente situazione:

Reimpostiamo la tabella nella maniera seguente:

4. Integriamo i dati da un foglio Excel

Adesso procediamo integrando i dati da un foglio Excel, per calcolare le provvigioni per ciascun agente.

Importiamo anzitutto i dati andando su Home > Dati > Recupera dati. Selezioniamo Excel. (c’è anche il collegamento veloce sotto Dati)

Selezioniamo il file excel anagrafica_clienti.xlsx.

Selezioniamo entrambe le tabelle e clicchiamo su Carica.

Andando su Modello vedremo che Power BI avrà collegato tutte le tabelle totalmente a caso.

Clicchiamo col destro su una delle due, poi andiamo su Gestisci relazioni, usando SHIFT e il mouse selezioniamo le relazioni che interessano Compensi agenti e Anagrafica Clienti (nella maniera mostrata nell’immagine) e clicchiamo su Elimina per tutte le relazioni selezionate (e create).

Ricreiamo le relazioni nella maniera seguente:

Fatto questo torniamo sulle tabelle e andiamo su vendite_x_agenti, dove abbiamo aggiunto prima i dati di vendita.

Clicchiamo col destro su vendite_x_agenti e selezioniamo Modifica query. Dalla finestra di modifica andiamo su Home > Combina > Merge query.

Impostiamo l’unione nella maniera seguente:

Clicchiamo sul pulsante in alto a destra della nuova colonna aggregata:

Selezioniamo Compenso e Fisso nella maniera seguente:

Salviamo il tutto e chiudiamo. Clicchiamo col destro sulla tabella e aggiungiamo una Nuova colonna. Inseriamo la seguente formula:

provvigione = vendite_x_agente[totale_importo]*vendite_x_agente[Compensi agenti.Compenso]

In questo modo calcoliamo il compenso in percentuale sul totale venduto. Torniamo sul report e aggiungiamo alla tabella anche la provvigione. Dovremo arrivare a vedere qualcosa di simile:

5. Formattazione valori

A questo punto vogliamo formattare i valori delle vendite nel formato valuta. Essendo dati aggregati in una tabella generata da JOIN, possiamo anzitutto formattare i valori all’origine, nelle tabelle di partenza. Questo vuol dire che ci spostiamo su vendite.

Selezioniamo la colonna desiderata ed inseriamo il formato Valuta. Possiamo modificare il tipo di valuta cliccando sull’opportuno pulsante come nell’immagine precedente.

Spostiamoci adesso su vendite_x_agente. Clicchiamo sulla colonna totale_importo, da Tipo dati selezioniamo Numero decimale, da Formato selezioniamo Valuta come prima. Stesso discorso per la provvigione.

Fatto questo possiamo tornare sulla visualizzazione dei dati. Dove vedremo qualcosa di simile a questo:

6. Creazione di Drill-through

Adesso vogliamo creare una analisi dettagliata per il totale venduto da ogni agente.

Aggiungiamo anzitutto una seconda pagina che chiameremo VENDITE AGENTE

Aggiungiamo una scheda per il titolo dell’agente analizzato:

Impostiamo una scheda che mostri anche il totale venduto nella maniera seguente:

Adesso aggiungiamo l’importo del venduto per ciascun agente per ciascuna città, procedendo nella maniera seguente:

Fatto questo attiviamo il campo Drill-thorugh sul nominativo dell’agente. Per farlo procediamo nel modo seguente:

Fatto tutto questo andiamo sulla pagina VENDITE. Clicchiamo col destro su un nominativo agente e scegliamo Drill-thought > VENDITE AGENTE.

Visualizzeremo i dati dell’agente nel report VENDITE AGENTE creato in precedenza.

Fatto questo abbiamo creato il collegamento Drill-through che volevamo.

[ubuntu] Installare Java 8 su Ubuntu 14.04

Java 8 è stato rilasciato nel marzo 2014 ed è disponibile, all’interno delle repository ufficiali di Ubuntu, solo per le versioni Ubuntu 14.10 e superiore.

Per poterlo installare su Ubuntu 14.04 bisogna procedere nel modo seguente, installando OpenJDK 8 dalla PPA repository.

Apriamo il terminale e aggiungiamo la repository digitando:

Aggiorniamo l’apt-get digitando:

A questo punto possiamo procedere all’installazione:

Se dovessero sorgere problemi con le dipendenze digitiamo:

Dopodiché possiamo eseguire nuovamente il comando precedente per procedere con l’installazione.

[mysql] Creare tabella pivot dinamica in MySQL (per esordienti totali)

Con il MySQL è possibile generare tabelle pivot dinamiche, ovvero che contengano nomi di colonne automatiche, in base ad una tabella di riferimento.

Quello che vogliamo ottenere sarà un risultato come il seguente:

Prima di cominciare creiamo un database con un po’ di dati in modo da poterci lavorare.

1. Creazione dati di partenza

Creiamo 3 tabelle: prodotti, agenti e vendite. Di seguito riporto le query per creare le singole tabelle ed inserire i dati di esempio.

PRODOTTI

Per creare la tabella prodotti eseguiamo la seguente query.

Inseriamo i dati nel modo seguente:

AGENTI

Andiamo adesso a creare la tabella degli agenti, in modo analogo:

Ed inseriamo i dati:

VENDITE

Per le vendite andremo a creare la tabella in questo modo:

A differenza delle precedenti due, qui voglio inserire dei dati casuali. Per inserire una riga di dati casuali, pescati dalle precedenti due tabelle, potremmo scrivere:

Faccio notare che con l’istruzione ROUND(1+RAND()*4,0) inseriamo un valore intero casuale tra 1 e 5. Se volessimo generalizzare il procedimento potremmo scrivere ROUND(n+RAND()*(m-n),0) dove n è il minimo, mentre m è il massimo.

Con n = 3 e m = 8 avremmo infatti le seguenti operazioni:

  1. RAND() genera un valore casuale decimale da 0 a 1
  2. Moltiplicando per (8-3) il valore casuale sarà tra 0 e 5.
  3. Sommano il risultato a 3 il valore casuale sarà un decimale tra 3 e 8. Potrebbe essere per esempio 6,4.
  4. Usando ROUND() arrotondiamo a 0 cifre decimali ottenendo quindi un intero.

Se volessimo inserire più di una riga in una singola operazione, possiamo farlo scrivendo una procedura.

Dichiariamo quindi una procedura nel modo seguente, che inserisca 1000 valore casuali per volta.

Chiamiamo la procedura digitando:

2. Creazione tabella pivot

Per creare una tabella pivot manualmente utilizziamo CASE WHEN ... END. A mano potremmo scrivere una query come quella di seguito:

Ogni colonna della pivot sarà generata da:

In questo caso noi abbiamo una tabella dei prodotti, dove sappiamo esserci all’id = 1 il prodotto chiamato mele.

Con SUM() sommiamo i valori (avremmo potuto usare COUNT(), AVG(), MAX(), MIN() ecc.) e con ROUND() arrotondiamo. Quest’ultima funzione in particolare non sarebbe necessaria, ma la utilizzo solo perché, visto che si parla di importi in euro, non ha senso calcolare un risultato al di sotto dei centesimi.

Quello che vogliamo fare ora è poter scrivere, quel pezzo di query, in modo iterativo, ripetendola per CIASCUN valore della tabella prodotti.

In particolare potremmo eseguire una query come la seguente:

Il risultato di questa query sarebbe un singolo campo contenente i seguenti valori:

Faccio notare che grazie a GROUP_CONCAT() vengono inserite le virgole tra le singole righe.

Andiamo a creare quindi una procedura come la seguente:

Eseguiamo, come prima, la procedura:

Otterremo il risultato cercato.

Dobbiamo usare una procedura per evitare di incorrere in una serie di incongruenze legate all’interrogazione del database.

DIfatti, usando il PHPMyAdmin e lanciando solamente l’istruzione:

Si incorrere nel seguente errore:

Fatal error: Uncaught Error: Call to a member function getClauses() on null in D:\xampp\phpMyAdmin\vendor\phpmyadmin\sql-parser\src\Utils\Query.php:564 Stack trace: #0 D:\xampp\phpMyAdmin\vendor\phpmyadmin\sql-parser\src\Utils\Query.php(681): PhpMyAdmin\SqlParser\Utils\Query::getClause(NULL, NULL, 'ORDER BY', -1, false) #1 D:\xampp\phpMyAdmin\libraries\DisplayResults.php(1385): PhpMyAdmin\SqlParser\Utils\Query::replaceClause(NULL, NULL, 'ORDER BY', '') #2 D:\xampp\phpMyAdmin\libraries\DisplayResults.php(4376): PMA\libraries\DisplayResults->_getUnsortedSqlAndSortByKeyDropDown(Array, '') #3 D:\xampp\phpMyAdmin\libraries\sql.lib.php(1689): PMA\libraries\DisplayResults->getTable(Object(mysqli_result), Array, Array, false) #4 D:\xampp\phpMyAdmin\libraries\sql.lib.php(1980): PMA_getHtmlForSqlQueryResultsTable(Object(PMA\libraries\DisplayResults), './themes/pmahom...', NULL, Array, false, 6, 6, NULL, Object(mysqli_result), Array) #5 D:\xampp\phpMyAdmin\libraries\sql.lib.php(2199): PMA_getQueryResponseForResultsReturned(Object(my in D:\xampp\phpMyAdmin\vendor\phpmyadmin\sql-parser\src\Utils\Query.php on line 564

3. Utilizzo della tabella nel PHP

Leggiamo la tabella tramite il PHP. Per farlo utilizzerò la classe MySQLdb come in questo esercizio sul MySQL Cluster.

Creiamo nella root del nostro sito un file MySQLdb.php contenente il seguente codice:

Creiamo adesso un file index.php, nella stessa posizione, contenente il seguente codice:

Vediamo in particolare come nel vettore $prodotti abbiamo l’elenco di tutti i prodotti e quindi delle colonne della pivot, che si trovano in $dati. Il risultato che otterremo sarà simile a questo:

 

Google Drive, upload bloccato su “meno di un minuto rimanente”

Problema: quando si cerca di caricare su Google Drive un documento di dimensioni consistenti (nel mio caso il problema si presentava con file di appena qualche MB) l’upload non riesce ad andare a buon fine e si blocca su un caricamento simile a quello nell’immagine, dando per tempo stimato “Meno di un minuto rimanente”

Soluzione: il problema può dipendere da Kaspersky Internet Security. Dalle Impostazioni di rete disattivare Scansione delle connessioni crittografate.

Più nel dettaglio ho notato che questo problema affligge tutti gli upload via web. Anche tentando il caricamento altrove, non solo su Google Drive, ed utilizzando qualsiasi browser (ho trovato indistintamente il medesimo problema sia su Chrome, Firefox che Edge).

In generale il problema si presenta come l’impossibilità di stimare il tempo di upload necessario, per cui qualunque barra di upload arriva subito alla fine e si blocca lì fino al completamente del medesimo.

Il problema dipende da Kaspersky Internet Security, nel mio caso ho verificato il problema sulla versione 20.0.14.1085 (j) con Windows 10 x64 Build 18362.

Per risolvere il problema aprire Kaspersky Internet Security > Impostazioni > Avanzate > Rete (Impostazioni di rete) > Scansione delle connessioni crittografate

Selezionare Non esaminare le connessioni crittografate.

Come utilizzare su Linux l’SFTP per trasferire e gestire i file da riga di commando

L’SFTP (SSH File Transfer Protocol) è un protocollo simile al FTP, utilizzato però per trasferire e manipolare file mediante SSH.

I comandi utilizzati sono simili a quelli del FTP. E’ molto utile specialmente quando si devono trasferire i file da un server all’altro.

1. Collegarsi in SFTP

Per collegarci al server remoto in SFTP digitiamo:

Per collegarci al server remoto su una porta diversa dalla 22

Una volta collegati ci verrà richiesta la password.

2. Comandi disponibili in SFTP

Per ottenere l’elenco di tutti i comandi disponibili, digitiamo:

L’output sarà simile al seguente:

bye Quit sftp
cd path Change remote directory to ‘path’
chgrp grp path Change group of file ‘path’ to ‘grp’
chmod mode path Change permissions of file ‘path’ to ‘mode’
chown own path Change owner of file ‘path’ to ‘own’
df [-hi] [path] Display statistics for current directory or filesystem containing ‘path’
exit Quit sftp
get [-Ppr] remote [local] Download file
reget remote [local] Resume download file
help Display this help text
lcd path Change local directory to ‘path’
lls [ls-options [path]] Display local directory listing
lmkdir path Create local directory
ln [-s] oldpath newpath Link remote file (-s for symlink)
lpwd Print local working directory
ls [-1afhlnrSt] [path] Display remote directory listing
lumask umask Set local umask to ‘umask’
mkdir path Create remote directory
progress Toggle display of progress meter
put [-Ppr] local [remote] Upload file
pwd Display remote working directory
quit Quit sftp
rename oldpath newpath Rename remote file
rm path Delete remote file
rmdir path Remove remote directory
symlink oldpath newpath Symlink remote file
version Show SFTP version
!command Execute ‘command’ in local shell
! Escape to local shell
? Synonym for help

3. Scaricare file e cartelle dal SFTP

Per scaricare un singolo file, nella posizione nella quale abbiamo aperto l’SFTP, digitiamo:

Per scaricare un file rinominandolo oppure scaricandolo in una posizione locale diversa:

Per scaricare una cartella digitiamo:

Per scaricare tutti i file della cartella corrente remota nella cartella locale attuale:

4. Caricare file e cartelle sul SFTP

Per caricare un file locale nella posizione remota, digitiamo:

Per caricare una cartella locale sul server remoto digitiamo:

Per caricare tutti i file della cartella locale sul server remoto:

5. Manipolare file e cartelle sul SFTP

Vedere tutto il contenuto di una cartella:

Creare una cartella:

Rinominare un file:

Rimuovere un file:

Rimuovere una cartella:

[vba] Classe per leggere e scrivere su un database MySQL

A seguito del precedente articolo [excel] Aggiungere all’origine dati delle tabelle da un database MySQL ho deciso di integrare l’esercizio creando una classe per leggere e scrivere tramite VBA su un database MySQL.

Affinché la classe funzioni ricordiamoci di installare il connettore recuperabile sul sito ufficiale (Connector/ODBC 8.0.19). Inoltre ricordiamoci anche che per poter eseguire la connessione ADO abbiamo bisogno di importare l’opportuna libreria dai riferimenti. In questo modo:

Detto tutto questo possiamo creare una classe MySQL con le seguenti istruzioni all’interno:

Possiamo usare la classe nel modo seguente:

Faccio notare che con il metodo clear possiamo aggiungere gli slash agli apici, presenti nel cognome.