martedì 28 luglio 2026

Free PlyxSQL© SQL Beta - 1.0.0.85 - Text to SQL

Free PlyxSQL© Beta - 1.0.0.85  - Text to SQL

POSTED BY GIULIANO PAGNINI, 28 LUG 2026

Free DOWNLOAD Clicca qui Info https://pgsoft.it/plyxhtml

Dal Designer al browser: un vero chatbot text-to-SQL

Lo Schema Designer, il Configuratore Semantico, la finestra "Genera prompt AI" con la sua esecuzione di verifica e la sua autocorrezione. Il passo successivo renderlo disponibile a tutti sul web.


La risposta è un web server scritto in C++Builder (WebBroker su Indy) che espone lo stesso motore — prompt semantico, esecuzione, sicurezza, autocorrezione — come una manciata di endpoint HTTP, più un client Vue che li consuma. Non è stata una riscrittura da zero: è stato il momento in cui tutto il lavoro fatto sul lato "server" del Configuratore Semantico (pensato fin dall'inizio per essere indipendente dall'interfaccia desktop) ha dimostrato di reggere davvero fuori da quel contesto.

Server C++Builder (service o stand-alone GUI Application)

Il cuore: stesso motore, architettura diversa

SDServerPromptBuilder — il componente che trasforma una domanda in un prompt strutturato per l'AI — non ha richiesto una sola riga di modifica per girare sul web server. Era già stato progettato per non dipendere da nulla di specifico del Designer: solo RTL, nessuna dipendenza da componenti visuali. La differenza vera è stata nel come orchestrarlo.

Nel Designer, tutto girava sull'interfaccia utente: bisognava restare asincroni per non bloccare la finestra mentre si aspettava una risposta AI. Su un web server, ogni richiesta HTTP ha già il proprio thread — bloccarlo per la durata di una chiamata è normale, atteso, persino più semplice da scrivere. Lo stesso ciclo (prompt → AI → controllo di sicurezza → esecuzione → eventuale correzione) è diventato un semplice ciclo sincrono, senza bisogno dell'architettura a callback che serviva sul desktop.

Nessuno sconto sulla sicurezza

Il guardrail costruito per il Designer — solo SELECT di sola lettura, niente scritture, niente statement multipli — è arrivato intatto sul server. Ha senso: se qualcosa deve essere rigoroso, è proprio il confine tra "un chatbot può proporre una query" e "un chatbot può eseguire qualcosa contro un database di produzione". Ogni query, prima di toccare il database, passa dallo stesso controllo testuale rigoroso — e se anche l'AI dovesse inventarsi qualcosa di strano, il controllo non fa eccezioni per nessuno.

Il ciclo di autocorrezione ha guadagnato per strada un affinamento non banale: se un errore di esecuzione si ripete identico dopo che l'AI ha già prodotto una query diversa, il sistema smette di insistere. È nato da un caso reale — un errore di configurazione del database (non della query) che veniva rimandato all'AI tre volte di fila, sprecando ogni tentativo su qualcosa che nessuna riscrittura del SQL avrebbe mai potuto risolvere. Ora quel pattern viene riconosciuto e segnalato subito come probabile problema di infrastruttura, non di query.

Vedere cosa sta succedendo, non solo aspettare

Qui è dove le cose si sono fatte interessanti. Le prime versioni rispondevano in un unico blocco: silenzio totale, poi tutto insieme. Con un modello locale (Ollama) che può metterci anche un minuto a rispondere, quel silenzio è indistinguibile da un sistema bloccato.

La soluzione è stata disaccoppiare l'avvio dall'attesa: il client avvia il lavoro (che gira su un thread in background), riceve subito un identificativo, e interroga a ripetizione lo stato — un pattern di polling piuttosto che una singola chiamata bloccante. Da lì è nato un ticker che scandisce i secondi in tempo reale, e poi qualcosa di più preciso: passando alla modalità streaming di Ollama, il primo pezzo di testo che arriva diventa il confine naturale tra "il modello si sta ancora caricando/elaborando" e "sta generando davvero" — una distinzione che con una singola risposta bloccante non era osservabile in nessun modo. Il risultato: tre fasi visibili in tempo reale nel client, ognuna basata su un segnale vero, mai un'etichetta inventata.

Una cache che impara da sola

Sul Designer, la cache si alimentava da un gesto esplicito dell'operatore: un bottone "Verifica e salva come esempio". Sul server quel passaggio manuale è sparito del tutto — ogni volta che una domanda va a buon fine, la coppia domanda/query viene registrata automaticamente, perché un successo sul server è già una verifica reale contro il database. Nessuno deve ricordarsi di salvare nulla.

Stesse due soglie di sicurezza già validate sul Designer: corrispondenza esatta prima, corrispondenza approssimata solo sopra una soglia molto alta, e — il dettaglio a cui teniamo di più — mai un match se i numeri nelle due domande non coincidono. "Fatture 2024" e "fatture 2023" restano sempre due domande diverse, per quanto si somiglino nel resto della frase. E prima di restituire una risposta dalla cache come definitiva, il sistema la riesegue comunque per conferma: se lo schema o i dati sono cambiati nel frattempo, se ne accorge da solo e chiede una risposta fresca invece di rischiare.

Un file per portarsi via il risultato

Client Vue.js con Vuelityx

La tabella mostrata in chat è volutamente un'anteprima limitata (configurabile, 10 righe di default) — serve a confermare che la query funzioni, non a sostituire un vero export. Per quello c'è un endpoint dedicato che riesegue la stessa query, già passata dal controllo di sicurezza, con un tetto molto più alto, e restituisce un CSV vero e proprio, scaricabile con un click. Un dettaglio che conta più di quanto sembri: punto e virgola come separatore, non virgola — perché Excel in locale italiano usa la virgola come separatore decimale, e con il separatore sbagliato il file si aprirebbe tutto incolonnato in un'unica cella.

Sapere cosa sta succedendo, in aggregato

Ogni domanda che arriva a un esito — riuscita, fallita, risolta dalla cache — viene registrata in modo silenzioso: quanti tentativi sono serviti, quanto ci ha messo, se è arrivata dalla cache o dall'AI. Un endpoint restituisce il quadro aggregato: percentuale di successo, tempo medio, gli errori più frequenti. È il dato che dice dove guardare quando qualcosa non va, invece di doverlo dedurre osservando il client in tempo reale — è così, tra l'altro, che abbiamo diagnosticato un problema di configurazione FireDAC che altrimenti sarebbe sembrato un errore casuale dell'AI.

Il client: niente di più di quanto serva

Dall'altra parte, un frontend Vue essenziale — bolle di conversazione, evidenziazione del testo generato, una tabella per i risultati, un link per il CSV completo. Niente framework pesanti, niente stato complesso: solo quello che serve per rendere leggibile ciò che il server produce, con un dettaglio di attenzione che vale la pena raccontare — durante lo sviluppo, un bug di reattività (Vue 3 non sempre traccia le mutazioni su un oggetto se non è stato reso "reattivo" fin dall'inizio) faceva sì che l'interfaccia restasse bloccata sui primi tre puntini per sempre, qualunque cosa succedesse davvero lato server. Un promemoria utile: anche l'interfaccia più semplice ha i suoi dettagli sottili, e vale la pena controllarli con la stessa cura riservata al motore che sta dietro.


#TextToSQL #AI #DatabaseLegacy #SQL #Firebird #CodeGeneration #SoftwareArchitecture #DataEngineering #LLM #PromptEngineering #DigitalTransformation #PubblicaAmministrazione #SoftwareDevelopment #TechInnovation #PlyxSQL

lunedì 27 luglio 2026

Free PlyxSQL© SQL Beta - 1.0.0.84 - Text to SQL

Free PlyxSQL© Beta - 1.0.0.84  - Text to SQL

POSTED BY GIULIANO PAGNINI, 27 LUG 2026

Free DOWNLOAD Clicca qui Info https://pgsoft.it/plyxhtml


Da "genera una query" a "fidati del risultato": l'ultimo giro di lavoro sul motore text-to-SQL

Qualche settimana fa avevamo raccontato come il Configuratore Semantico avesse chiuso sei falle silenziose nel motore che traduce domande in linguaggio naturale in query SQL. Quel lavoro rispondeva a una domanda: l'AI ha capito bene lo schema del database? Ma c'era una domanda più scomoda che restava aperta: e se avesse capito bene la domanda, ma sbagliato comunque la query? E se qualcuno ponesse una domanda che, con la formulazione giusta, potesse far scrivere all'AI qualcosa di pericoloso?

L'ultimo giro di lavoro parte esattamente da lì. Non abbiamo aggiunto un modello più potente o un prompt più lungo — abbiamo aggiunto quello che mancava perché il sistema potesse fidarsi delle proprie risposte, invece di limitarsi a produrle.

Il cambio più importante: eseguire, non solo generare

Fino a poco fa, il flusso era: domanda in ingresso, SQL in uscita, testo mostrato a schermo. Nessuno controllava se quel SQL fosse davvero valido, se le colonne esistessero per davvero, se ci fosse un errore di sintassi nascosto in una condizione complicata. Il primo a scoprirlo era l'utente, alla peggio in produzione.

Ora la query generata viene eseguita davvero contro il database — con un tetto di righe restituite, giusto per validare, non per produrre un report — prima di essere mostrata come definitiva. E se fallisce? Qui sta il pezzo più soddisfacente di tutto il lavoro: l'errore vero restituito dal database viene rimandato all'AI, che tenta una correzione. Fino a tre tentativi, poi ci si ferma e si mostra l'ultimo errore senza fingere che vada tutto bene. Un nome di colonna scritto in modo leggermente sbagliato, un tipo di dato incompatibile — la maggior parte di questi errori si risolve da sola al secondo tentativo, con il messaggio d'errore giusto in mano.

Accanto a questo, un guardrail di sicurezza che non fa sconti: solo SELECT di sola lettura. Niente DROP, DELETE, UPDATE, niente più di uno statement nella stessa risposta. Non è un controllo "quasi sicuro" — è deliberatamente severo, con la filosofia che in caso di dubbio si rifiuta, anche a costo di qualche falso positivo su una query insolita ma legittima.

E per chi vuole verificare una query ottenuta fuori dal programma — magari incollando il prompt in un altro strumento e portando indietro il risultato — c'è ora un bottone "Testa SQL" che applica esattamente gli stessi controlli, senza passare dall'AI.

Una cache che non si fida ciecamente di se stessa

Ogni domanda, anche identica a una già fatta, richiamava l'AI da zero. Ora no: le domande verificate con successo (tramite il nuovo bottone "Verifica e salva come esempio") diventano candidate per una cache a due livelli — corrispondenza esatta, e corrispondenza approssimata con una soglia alta.

Il dettaglio a cui teniamo di più: la cache non si fida ciecamente di se stessa. Prima di restituire una risposta cache-hit come definitiva, la ri-esegue per conferma. E se la configurazione semantica della tabella coinvolta è cambiata da quando l'esempio è stato verificato, se ne accorge da sola e chiede una risposta fresca invece di rischiare. Anche il rischio più insidioso di una cache testuale — confondere "fatture 2024" con "fatture 2023" solo perché le due frasi si somigliano — è gestito esplicitamente: un controllo separato confronta i numeri delle due domande, e se non coincidono il match viene scartato, qualunque sia la somiglianza del resto della frase.

Domande che si ricordano di quella prima

Un piccolo tassello, ma che cambia parecchio l'esperienza d'uso: ora è possibile spuntare "mantieni il contesto della domanda precedente", e una domanda come "e nel 2025?" dopo "utenti in mora nel 2024" viene interpretata correttamente come una variazione, non come una domanda a sé stante e incomprensibile. La decisione se collegare le due domande resta sempre dell'AI, in base al testo reale — nessun collegamento forzato quando non ha senso.

Sapere dove investire tempo, senza doverlo indovinare

Fino a ieri, l'unico modo per sapere se la configurazione funzionava bene era testarla a mano. Ora ogni domanda posta realmente in produzione viene registrata in modo silenzioso — sorgente (cache o AI), tabelle coinvolte, esito. Una finestra dedicata mostra il quadro aggregato: percentuale di richieste risolte dalla cache, tasso di successo, tabelle ed errori più frequenti. È il dato che dice dove mettere le mani la prossima volta, invece di doverlo indovinare guardando i log a occhio.

Chi può vedere cosa

L'ultima aggiunta strutturale: permessi per ruolo su tabelle e singoli campi. Un ruolo può non vedere l'esistenza stessa di una tabella riservata, o vedere una tabella ma non uno dei suoi campi. La parte importante, quella su cui abbiamo insistito di più: il controllo vero vive solo nel componente server, quello che riceve un ruolo già autenticato da chi lo interpella — non nel Designer, dove esiste solo un'anteprima etichettata chiaramente come tale, utile per verificare la configurazione ma mai spacciata per un confine di sicurezza reale.

Le rifiniture che si notano solo quando mancano

Un po' di lavoro è andato anche in cose meno appariscenti ma che si sentono nell'uso quotidiano:

  • Le celle che prima accettavano testo libero per cardinalità, tipo di join, o valore di un parametro dinamico ora offrono tendine a scelta vincolata — impossibile scrivere un valore che il sistema non riconoscerebbe.
  • Le espressioni SQL lunghe, nei popup di modifica, vengono ora formattate ed evidenziate automaticamente, con un bottone per riformattare su richiesta — niente più muri di testo su una riga sola.
  • Un controllo al salvataggio avvisa se un filtro condizionale rischia di non attivarsi mai, perché le sue parole chiave non compaiono da nessuna parte tra quelle che decidono se includere la tabella nel prompt.
  • Una Suite di Regressione riesegue automaticamente gli esempi noti, per accorgersi subito se una modifica alla configurazione ha rotto qualcosa che prima funzionava.

Il filo conduttore, di nuovo

Lo stesso di sempre, solo applicato a un pezzo diverso del problema: un sistema affidabile non nasce da un salto tecnologico, nasce da mille decisioni su cosa fare quando qualcosa va storto. Eseguire prima di mostrare. Rifiutare prima di rischiare. Ricontrollare prima di fidarsi della cache. Avvisare prima di lasciare che un problema resti invisibile fino a quando qualcuno lo scopre nel modo peggiore.

Non è il genere di lavoro che finisce in una demo entusiasmante. È il genere di lavoro che decide se, tra sei mesi, qualcuno userà ancora questo strumento — o avrà smesso dopo la prima risposta sbagliata di cui nessuno si è accorto.


#TextToSQL #AI #DatabaseLegacy #SQL #Firebird #CodeGeneration #SoftwareArchitecture #DataEngineering #LLM #PromptEngineering #DigitalTransformation #PubblicaAmministrazione #SoftwareDevelopment #TechInnovation #PlyxSQL

mercoledì 22 luglio 2026

Free PlyxSQL© SQL Beta - 1.0.0.81 - Text to SQL

 Free PlyxSQL© Beta - 1.0.0.81  - Text to SQL

POSTED BY GIULIANO PAGNINI, 23 LUG 2026

Free DOWNLOAD Clicca qui Info https://pgsoft.it/plyxhtml



1. Few-shot examples: mostrare invece di spiegare

Per ogni tabella si può ora configurare un piccolo set di coppie domanda → SQL già validate da un operatore umano. Non sono documentazione: finiscono letteralmente nel prompt come esempi di riferimento.

È il tipo di intervento che nella letteratura sul text-to-SQL ha il rapporto costo/beneficio più alto: una descrizione testuale di un JOIN complesso o di una CASE particolare lascia sempre margine di interpretazione, un esempio concreto no. E quando la domanda dell'utente somiglia a un esempio già validato, il modello smette di "indovinare" lo stile giusto e inizia a copiarlo.

2. Filtri incondizionati: la differenza tra "se serve" e "sempre"

Il configuratore aveva già i Keyword Filter: un filtro WHERE che scatta se una parola specifica compare nella domanda. Utile, ma con un buco di sicurezza evidente — se l'operatore non usa la parola giusta, il filtro semplicemente non scatta. Un record cancellato può finire in una query senza che nessuno l'abbia chiesto.

Gli always_filters risolvono esattamente questo: espressioni WHERE che vengono applicate sempre quando la tabella è coinvolta, indipendentemente da cosa scrive l'utente. Non sono un'opzione tra le tante nel prompt — arrivano accompagnate da un'istruzione esplicita che dice al modello: questo non è negoziabile, non è un'ipotesi, va sempre in AND. Soft delete, isolamento multi-tenant, esclusione di record di sistema: tutto ciò che deve valere a prescindere ora ha un posto dove stare.

3. Il formato che invecchia bene

Ogni volta che un formato di scambio dati vive abbastanza a lungo, arriva il giorno in cui cambia. Il pacchetto semantico esportato per il componente server ora porta un format_version come primo campo. Non è burocrazia: è la differenza tra un server che sa di dover ignorare educatamente un campo che non conosce ancora, e un server che lo interpreta male senza accorgersene. Non abbiamo aggiunto un blocco rigido — solo un avviso, mai un errore: forward-compatibility onesta, non difensiva all'eccesso.

4. Quando la domanda nomina due cose, non una

Questo è il bug più subdolo che abbiamo trovato. Il sistema aveva un meccanismo per mappare, ad esempio, il nome di un comune al suo codice interno — ma restituiva sempre un valore, quello di default. Se la domanda dell'utente diceva "confronta le occupazioni suolo tra Riccione e Gatteo", il sistema silenziosamente ignorava Gatteo e rispondeva solo per Riccione. Nessun errore, nessun avviso — solo una risposta a metà, spacciata per completa.

Ora ogni valore configurato porta un flag matched calcolato contro il testo reale della domanda, e quando più varianti dello stesso parametro risultano nominate esplicitamente, il prompt le espone tutte insieme in una sezione dedicata — con un'istruzione che vieta esplicitamente al modello di sceglierne una sola. Da lì il modello costruisce un IN (...) o l'unione che serve. La differenza tra "sembra funzionare" e "funziona davvero" spesso sta proprio in questo genere di casi limite.

5. Cosa succede quando lo schema ha 300 tabelle

Un prompt che include "tutte le tabelle perché non abbiamo capito quale serve" è già una toppa accettabile su uno schema piccolo. Su uno schema con centinaia di tabelle configurate diventa un problema serio: costo in token, e soprattutto rumore che confonde il modello più di quanto lo aiuti.

Abbiamo introdotto una soglia oltre la quale il sistema non include più tutto, ma ordina le tabelle candidate per un punteggio di pertinenza (il nome tabella nella domanda pesa più di una singola keyword) e tiene solo le migliori. Sempre con un avviso esplicito su quante e perché sono state escluse — mai un troncamento silenzioso che l'utente scopre solo quando manca qualcosa.

6. Quando "occupazione" nella configurazione non trova "occupazioni" nella domanda

L'ultimo pezzo è forse quello con il ritorno più immediato sulla qualità percepita. Il motore di riconoscimento delle tabelle cercava corrispondenze esatte, parola per parola. Se una keyword era configurata al singolare e l'utente scriveva al plurale, semplicemente non scattava — e il sistema, non trovando nulla, finiva dritto nel fallback "includi tutto".

Ora, solo dopo che il match esatto ha fallito, entra in gioco un secondo tentativo più permissivo: confronto per distanza di edit tra le parole, capace di riconoscere plurali, generi, piccoli refusi. Non è magia — non copre sinonimi concettualmente diversi, quello richiederebbe tutt'altro tipo di motore — ma chiude una fetta enorme dei "non ho capito la domanda" più frustranti, quelli dove la domanda era in realtà perfettamente chiara a un essere umano.

Un dettaglio non banale: questo fallback approssimato vale solo per decidere quali tabelle mostrare come contesto. Non tocca mai i filtri o i valori che finiscono letteralmente nel SQL generato — lì un match "quasi giusto" cambierebbe il risultato della query, non solo il contesto, ed è un rischio che semplicemente non vale il beneficio.

Il filo conduttore

Se c'è una lezione in tutto questo, è che un sistema text-to-SQL affidabile non nasce da un prompt più lungo o da un modello più potente. Nasce da mille piccoli casi limite trattati uno per uno, ciascuno con la stessa domanda di fondo: cosa succede davvero quando l'utente scrive qualcosa che non avevo previsto? A volte la risposta è "fallisci in modo rumoroso, con un avviso chiaro". Altre volte è "prova un secondo approccio, più permissivo, ma dillo". Non è mai "fai finta che vada tutto bene".

È un lavoro meno appariscente di un nuovo modello o di un prompt più elaborato. Ma è quello che, alla fine, decide se un utente si fida del sistema oppure smette di usarlo dopo la prima risposta sbagliata.



#TextToSQL #AI #DatabaseLegacy #SQL #Firebird #CodeGeneration #SoftwareArchitecture #DataEngineering #LLM #PromptEngineering #DigitalTransformation #PubblicaAmministrazione #SoftwareDevelopment #TechInnovation #PlyxSQL

lunedì 20 luglio 2026

Free PlyxSQL© SQL Beta - 1.0.0.79 - Text to SQL

Free PlyxSQL© Beta - 1.0.0.79  - Text to SQL

POSTED BY GIULIANO PAGNINI, 20 LUG 2026

Free DOWNLOAD Clicca qui Info https://pgsoft.it/plyxhtml

Il Configuratore Semantico plyxSQL: dalla mappatura dei campi a una vera base di conoscenza

Il Configuratore Semantico di plyxSQL Schema Designer è nato come un ponte tra lo schema fisico di un database e un modello linguistico chiamato a generare SQL a partire da domande in linguaggio naturale. Nelle ultime settimane si è arricchito di una serie di funzionalità pensate per un solo obiettivo: dare all'AI più contesto, riducendo al minimo gli errori di interpretazione — join sbagliati, campi inventati, valori "congelati" nel tempo.

Ecco cosa è cambiato.

1. Relazioni esplicite tra le tabelle


Fino a poco tempo fa, un lookup diceva solo "questo campo punta a quest'altra tabella" — ma non diceva come. Un JOIN su una relazione uno-a-molti può duplicare righe silenziosamente se non gestito con un GROUP BY; scegliere INNER invece di LEFT può far sparire dai risultati proprio i record che l'utente voleva vedere.

Ogni lookup ora può portare con sé due informazioni in più:

  • Cardinalità1:1, 1:N o N:1
  • Tipo di JOININNER, LEFT o RIGHT

Quando importi un lookup direttamente da una foreign key reale dello schema, il Designer propone già un valore sensato: N:1 come cardinalità tipica, e LEFT se il campo di riferimento è opzionale (nullable) — così un record senza quel collegamento non sparisce dai risultati per un dettaglio tecnico che l'utente non ha motivo di conoscere.

2. Chi rappresenta una riga? Il campo "identificatore umano"

Una domanda come "mostrami gli utenti" richiede all'AI di scegliere quale campo elencare — l'ID numerico non serve a nessuno. Ora un campo per tabella può essere marcato come identificatore umano (tipicamente una ragione sociale, un nome, una descrizione): quando la domanda non specifica quali colonne vuole, l'AI sa già cosa mostrare accanto alla chiave primaria, senza dover indovinare.

3. Cosa rappresenta davvero questa tabella?

I nomi fisici delle tabelle non sono sempre parlanti. SBEREGPERM non dice granché a un modello linguistico, per quanto bravo sia a indovinare gli acronimi. Ogni tabella può ora avere una descrizione libera — poche parole di contesto ("registrazioni permanenti") distinte dalle keyword di rilevamento, che restano espressioni booleane pensate per un altro scopo: decidere quando includere la tabella, non spiegarne il significato.

4. Una mappa per vedere lo schema semantico, non solo quello fisico

Configurare dieci, venti tabelle con keyword, lookup, filtri e campi calcolati produce, nel tempo, una configurazione che nessuno tiene più a mente per intero. Il Designer offre ora una vista dedicata — un grafico separato dallo schema fisico, raggiungibile con un bottone in sidebar — che mostra solo le tabelle effettivamente configurate, ciascuna con il proprio alias, la keyword principale e due contatori rapidi (filtri e campi calcolati configurati). Le relazioni tra tabelle appaiono come curve etichettate con cardinalità e tipo di join; passando il mouse su un nodo si vede il dettaglio completo — keyword intere, filtri con la loro espressione, lookup, tutto quello che il riquadro compatto non può mostrare senza affollare la vista.

Non è un doppione dello schema fisico: è la rappresentazione di quello che l'AI vede davvero quando genera una query.

5. Custom key che non invecchiano: le macro temporali

Molte configurazioni usano parametri come [[ANNO]] per puntare a tabelle organizzate per anno (SBEREGISTRO2026, e l'anno prossimo SBEREGISTRO2027). Fino a poco fa, il valore di quel parametro andava aggiornato a mano, una volta l'anno, da qualcuno che se lo ricordasse.

Ora il campo "Valore" di una custom key può contenere un'espressione dinamica — YEAR(TODAY()), CURRENT_DATE, YEAR(TODAY())-1 per l'anno precedente, e altre dodici — che viene risolta al valore vero nel momento in cui viene generata una domanda reale, non quando la configurazione viene salvata o esportata. Una combo dedicata, in fondo alla finestra di configurazione globale, elenca tutte le espressioni riconosciute: si seleziona la riga della tabella, si sceglie l'espressione dalla combo, ed è fatto.


Il punto tecnico interessante è quando avviene questa risoluzione — ed è anche il punto più facile da sbagliare, se non ci si pensa fin dall'inizio.

La scelta di risolvere l'espressione al momento della richiesta, e non prima, è quella che fa funzionare tutto il resto: il pacchetto configurato oggi resta corretto anche tra un anno, senza che nessuno debba ricordarsi di aggiornarlo — è il processore delle macro, non la configurazione, a occuparsi di restare aggiornato.

In sintesi

Nessuna di queste funzionalità, da sola, cambia radicalmente il configuratore. Messe insieme, spostano l'ago della bilancia da "un dizionario di mapping tra parole e colonne" verso qualcosa che si avvicina a una vera base di conoscenza: relazioni con un verso e una molteplicità precisi, tabelle che sanno spiegare cosa sono, valori che restano corretti senza manutenzione, e una mappa per vedere tutto questo a colpo d'occhio invece di ricostruirlo a memoria ogni volta.


#TextToSQL #AI #DatabaseLegacy #SQL #Firebird #CodeGeneration #SoftwareArchitecture #DataEngineering #LLM #PromptEngineering #DigitalTransformation #PubblicaAmministrazione #SoftwareDevelopment #TechInnovation #PlyxSQL

venerdì 17 luglio 2026

Free PlyxSQL© SQL Beta - 1.0.0.77 - Text to SQL

 Free PlyxSQL© Beta - 1.0.0.77  - Text to SQL

POSTED BY GIULIANO PAGNINI, 17 LUG 2026

Free DOWNLOAD Clicca qui Info https://pgsoft.it/plyxhtml

Configuratore semantico per il text to SQL

Perché un configuratore semantico è essenziale per il text-to-SQL su database legacy

Chi lavora con database gestionali storici — come quelli tipici della pubblica amministrazione o dei software verticali italiani — conosce bene il problema: campi chiamati IDUBICAZIONE, NGIURIDICA, STAG, tabelle con suffissi variabili come E_PUB[[ANNO]] o EREGTEMP[[ANNO]]. Nomi che hanno senso solo per chi ha scritto lo schema vent'anni fa, ma che diventano un ostacolo enorme quando si tenta di applicare un modello di linguaggio per generare SQL a partire da domande in linguaggio naturale.

Il problema dei nomi non convenzionali

Un LLM generico, senza contesto, non ha modo di sapere che NGIURIDICA = 1 significa "DITTA" o che IDCOMUNE va risolto tramite una tabella COMUNI con ref_field = ID. Senza un layer di mediazione, il modello può:

  • Inventare join inesistenti o sbagliare la cardinalità (confondendo relazioni 1:N con 1:1)

  • Interpretare male campi booleani mascherati da interi (CHIUSO, ESENTE, PAGATO)

  • Non riconoscere pattern di naming variabili per anno o comune, tipici di database multi-tenant o multi-periodo

Cosa fa davvero un configuratore semantico

Un configuratore semantico agisce come un dizionario vivo tra il linguaggio umano e lo schema fisico del database. Definisce esplicitamente:

  • Lookup e cardinalità: quali campi id vanno risolti in valori leggibili, e se il join è 1:1, 1:N o N:1 (fondamentale per evitare duplicazioni negli aggregati)

  • Placeholder dinamici: gestione di parametri come comune o anno che si propagano nei nomi di tabella, non solo nei valori

  • Campi calcolati: espressioni CASE o business logic che traducono codici interni in concetti di dominio (es. TIPO)

  • Filtri pre-validati: pattern di query complessi (subquery, condizioni di stato) già testati e riutilizzabili, evitando che il modello li reinventi ogni volta con margine di errore

Il valore concreto

Con questo approccio, la generazione SQL diventa deterministica e verificabile, non un'interpretazione statistica del modello. Il configuratore trasforma un database "illeggibile" in un'interfaccia semantica coerente, permettendo a chi pone la domanda — anche un utente non tecnico — di ottenere risultati corretti senza conoscere la struttura fisica sottostante.

Per chi sviluppa strumenti di code generation e automazione su schemi legacy, questo livello di configurazione non è un'opzione: è la differenza tra un text-to-SQL affidabile in produzione e un generatore di query plausibili ma potenzialmente sbagliate.


Semantic scheme










Ecco la query SQL generata per "Utenti in mora", con i placeholder [[COMUNE]] e [[ANNO]] risolti secondo i valori di default (riccioneG911, anno → anno corrente 2026), rispettando tutti i vincoli indicati (nessun filtro su IDCOMUNE, nessuna esclusione per ESENTE, uso del filtro esatto fornito in matched_filters).

Note sulla generazione

  • [[COMUNE]] è stato risolto in G911 (Riccione), essendo il comune marcato come defaultvalue: true in assenza di indicazioni diverse nella domanda.

  • [[ANNO]] è stato risolto in 2026, corrispondente all'anno corrente (YEAR(TODAY)), marcato come default.

  • Nessun filtro su ESENTE è stato applicato, coerentemente con il vincolo di non escludere questi record.

  • Nessun filtro su IDCOMUNE è stato inserito, come richiesto.

  • La condizione di mora è stata ripresa integralmente dal filtro fornito in matched_filters, senza modifiche, poiché non conteneva placeholder tra graffe da sostituire.

  • Non sono stati inclusi JOIN verso le tabelle di lookups poiché la domanda "Utenti in mora" non richiede la risoluzione di alcun valore leggibile aggiuntivo (es. nome ubicazione, comune, ecc.) e nessun campo lookup è necessario per la logica di filtro.

SELECT
  G911UTENTI.IDUTENTE,
  G911UTENTI.RAGIONE_SOCIALE,
 .....
  G911UTENTI.NAZIONE,
  CASE
    WHEN G911UTENTI.NGIURIDICA = 0 THEN 'FISICA'
    WHEN G911UTENTI.NGIURIDICA = 1 THEN 'DITTA'
    ELSE NULL
  END AS TIPO
FROM G911UTENTI
WHERE (G911UTENTI.CHIUSO IS NULL OR G911UTENTI.CHIUSO = 0)
  AND G911UTENTI.IDUTENTE IN (
    SELECT IDUTENTE
    FROM G911E_PUB2026
    WHERE (Pagato IS NULL OR Pagato = 0)
      AND (ANNULLATO IS NULL OR ANNULLATO = 0)
      AND (DATA > :CURRENT_DATE)
  )

#TextToSQL #AI #DatabaseLegacy #SQL #Firebird #CodeGeneration #SoftwareArchitecture #DataEngineering #LLM #PromptEngineering #DigitalTransformation #PubblicaAmministrazione #SoftwareDevelopment #TechInnovation #PlyxSQL


mercoledì 15 luglio 2026

Free PlyxSQL© SQL Beta - 1.0.0.75 - Text to SQL

Free PlyxSQL© Beta - 1.0.0.75  - Text to SQL

POSTED BY GIULIANO PAGNINI, 15 LUG 2026

Free DOWNLOAD Clicca qui Info https://pgsoft.it/plyxhtml

Configuratore semantico per il text to SQL



Dallo schema al prompt: il Configuratore Semantico di plyxSQL e le nuove Foreign Key

Se lavori con database di enti pubblici — tributi, affissioni, occupazioni di suolo — conosci bene il problema: schemi grandi, spesso non normalizzati, tabelle con nomi tag-based per comune e anno, e una crescente richiesta di "genera questa query con l'AI" da parte di chi in ufficio non scrive SQL tutti i giorni.

In questa versione dello Schema Designer di plyxSQL abbiamo aggiunto un pezzo intero dedicato esattamente a questo: il Configuratore Semantico. Non è un generatore di query — è lo strato che dice a un modello AI come leggere il tuo schema, prima ancora che scriva una riga di SQL. E già che c'eravamo, abbiamo sistemato e ampliato la gestione delle Foreign Key, che nel Designer era rimasta un po' indietro.

Vediamo cosa c'è di nuovo, con qualche esempio pratico.

Il problema di partenza

Immagina di dover chiedere a un'AI: "vorrei aggiornare le anagrafiche utenti con la PEC della tabella recapiti, solo se la PEC degli utenti è vuota". Per generare SQL corretto, l'AI ha bisogno di sapere:

  • quali tabelle sono coinvolte, e con che nome reale nel DB (spesso con prefissi tipo [[COMUNE]] e suffissi anno)
  • quali campi puoi davvero usare, e quali no (magari alcuni sono sensibili, o semplicemente irrilevanti)
  • come si collegano due tabelle, se serve un JOIN
  • quali regole di business valgono sempre ("non escludere mai i record ESENTE=1", "non filtrare per IDCOMUNE"...)

Passare tutto questo a mano, ogni volta, in un prompt scritto lì per lì, non è sostenibile. Il Configuratore Semantico lo fa una volta, dentro lo schema stesso, e da lì in poi genera il prompt corretto in automatico ad ogni domanda.

Configurare una tabella: le sei sezioni

Tasto destro su una tabella → ⚙ Configura semantica... apre un dialog con tutto quello che serve, organizzato in blocchi chiari:

1. Alias — il nome "vero" che la tabella deve avere nel prompt, placeholder inclusi: [[COMUNE]]UTENTI, [[COMUNE]]REGISTRO[[ANNO]].

2. Keyword di identificazione — le parole che, se presenti nella domanda, fanno capire all'AI (e al nostro motore di auto-detect) che questa tabella è rilevante. E qui la cosa si fa interessante: le keyword non sono semplici parole, sono espressioni booleane:

(utente+utenti+contribuente+matricola)-(insegne+occupazioni+cup)

Si legge: "se la domanda parla di utenti/contribuenti, MA non di insegne, occupazioni o CUP". Supportiamo + (OR), & (AND), - (NOT) e le parentesi, con la logica booleana standard — negare un gruppo tra parentesi nega il risultato complessivo, non termine per termine. Niente sorprese, tutto prevedibile.

3. Campi attivi, con alias di dominio — scegli quali campi finiscono nel prompt (perché no, non sempre vuoi esporre tutto), e per ognuno puoi aggiungere sinonimi: il campo fisico DESCRIZIONE nella tabella VIE può avere alias ubicazione, via, indirizzo — così se la domanda usa uno di questi termini, l'AI sa a cosa si riferisce davvero, anche senza nessun JOIN.

4. Lookup — qui si dice all'AI come risolvere un ID in un valore leggibile: UTENTI.IDCOMUNE punta a COMUNI.ID, e il campo da mostrare è COMUNI.DESCRIZIONE. Due modi per configurarlo:

  • a mano, in una griglia editabile;
  • trascinando direttamente nel canvas da un campo all'altro (con un mini-popup che chiede quale campo mostrare);
  • oppure, se hai già delle Foreign Key reali nello schema, con un click su "Importa da FK" che le legge tutte e propone i Lookup corrispondenti in automatico.

5. Campi calcolati — espressioni SQL con nome logico, tipo TIPO = CASE WHEN NGIURIDICA=0 THEN 'FISICA' ELSE 'DITTA' END.

6. Keyword filter — condizioni WHERE che scattano solo se la domanda contiene certe parole (stessa sintassi booleana della sezione 2), utile per filtri di dominio che non vuoi sempre attivi.

Le regole che valgono sempre: constraint e custom key

Tasto destro sul canvas → ⚙ Configurazione semantica globale... apre le impostazioni valide per ogni prompt generato:

  • Constraint generali: una per riga, es. "non filtrare mai per IDCOMUNE", "con UNION ALL non inserire GROUP BY".
  • Custom key, ora a quattro colonne — Parametro / Key / Valore / Default. Qui risolvi i placeholder: [[COMUNE]] può avere più valori possibili (riccione → G911, gatteo → H231), e la colonna Default dice all'AI quale usare se la domanda non specifica il comune.

Genera prompt AI: dal Designer direttamente al provider

Con tutto configurato, il comando "Genera prompt AI..." (menu Query, o il pulsante dedicato in toolbar) apre una finestra dove scrivi la domanda, scegli dialetto e versione (stessa combo già nota da "Export DDL"), e ottieni il JSON pronto — o lo invii direttamente al provider AI già configurato (Anthropic, OpenAI, Ollama), senza passare da un editor esterno.

Il nostro motore di rilevamento automatico decide da solo quali tabelle includere, in base a nome e keyword — se non trova corrispondenze, include tutte le tabelle configurate e te lo segnala, non genera mai un prompt "a metà" in silenzio.

Un passo oltre: il pacchetto per il server

Il Configuratore Semantico non serve solo per generare un prompt al volo dal Designer. Con "Esporta pacchetto semantico (server)..." ottieni un JSON completo — tutte le tabelle configurate, i lookup, i campi calcolati, le constraint globali — pensato per un componente server che riceve domande a runtime e deve rigenerare da sé lo stesso tipo di prompt, senza il Designer in mezzo. Motore booleano incluso, con specifica precisa per chi deve reimplementarlo in un altro linguaggio.

Le Foreign Key, finalmente al completo

Mentre eravamo lì, abbiamo chiuso alcuni buchi storici sulle FK nel Designer:

  • ON DELETE CASCADE evidenziato in rosso nel canvas — una CASCADE nascosta tra molte relazioni è un classico modo di perdere dati per errore, ora salta all'occhio anche solo scorrendo lo schema.
  • Dialog "Regole FK", finalmente collegato per davvero: se hai una FK selezionata, ne modifichi ON DELETE/ON UPDATE con due semplici tendine; se parti da una tabella senza FK selezionata, si apre invece una creazione guidata — scegli il campo sorgente, la tabella di destinazione (con aggiornamento automatico dei campi disponibili) e le regole, in un colpo solo.
  • Il disegno interattivo delle FK ora cattura correttamente il campo specifico da cui parti — prima, per un bug di vecchia data, finiva sempre per collegare la chiave primaria, anche se avevi trascinato da tutt'altro campo.

Produttività sul canvas

Un paio di comandi pensati per schemi grandi, dove scorrere/zoommare a mano per trovare una tabella diventa la parte più lenta del lavoro:

  • Trova tabella — una combo di ricerca in alto a sinistra: scegli la tabella, e la vista si centra lì.
  • Avvicina tabella — hai la tabella "attiva" selezionata e vuoi collegarci una FK verso una tabella che non è nemmeno visibile nello schema? Un click sposta quella tabella accanto a quella attiva (spostamento annullabile con Ctrl+Z, come un drag manuale), e centra la vista su entrambe.
  • Le tabelle con centinaia di campi non occupano più altezze infinite di canvas: oltre una certa soglia, i campi scorrono con la rotellina — stesso comportamento già noto dal Query Builder.
  • Zoom e posizione della vista vengono ora salvati con lo schema: riapri il progetto e sei esattamente dove avevi lasciato, non più tutto azzerato.

In breve

Il filo conduttore di questo giro di lavoro è uno solo: rendere lo schema autosufficiente per generare prompt AI corretti, senza che chi scrive la domanda debba conoscere i dettagli fisici del database — prefissi comune, suffissi anno, campi generici riusati con significati diversi in tabelle diverse. Tutto questo, configurato una volta nello Schema Designer, resta lì pronto per ogni nuova domanda — dal Designer stesso, o da un server che lo consulta a runtime.

Il prossimo passo naturale, su cui stiamo già ragionando, è la validazione lato server del SQL generato dall'AI prima di eseguirlo davvero — stesso principio di "non fidarsi ciecamente" applicato all'output, non solo all'input. Ne parliamo nel prossimo articolo.


#SQL #database #DataEngineering #plyxSQL #FireDAC #TextToSQL #Vuelityx #PGSOFT

lunedì 13 luglio 2026

Free PlyxSQL© SQL Beta - 1.0.0.71

Free PlyxSQL© SQL 

POSTED BY GIULIANO PAGNINI, 13 LUG 2026

Free DOWNLOAD Clicca qui Info https://pgsoft.it/plyxhtml

Profilare le query in PlyxSQL: un componente VCL con grafico in tempo reale


Il problema: "perché questa query è lenta?"

Chiunque lavori con FireDAC su più database (Oracle, SQL Server, PostgreSQL, MySQL, SQLite…) prima o poi si scontra con la stessa domanda: quanto ci mette davvero questa query, e perché? Il monitor integrato di FireDAC c'è e funziona, ma è pensato per il debug estemporaneo, non per restare agganciato all'applicazione e mostrare l'informazione a chi sta lavorando sulla query in quel momento.

Nell'ambito di plyxSQL, il mio tool di gestione SQL scritto in C++Builder, ho quindi costruito un componente dedicato. Due, in realtà: uno che misura, uno che disegna. Tenerli separati è stata la decisione architetturale più importante di tutto il lavoro.

Due componenti, due responsabilità

TFDQueryProfiler è il motore: un TComponent non visuale che esegue una TFDQuery o una TFDStoredProc cronometrando il tempo con TStopwatch, registra le righe coinvolte e, se richiesto, recupera il piano di esecuzione nativo del driver. Nessuna intercettazione automatica delle query esistenti — lo richiami esplicitamente quando vuoi profilare qualcosa:

auto res = FDQueryProfiler1->ProfileOnActiveConnection(
    L"SELECT * FROM Clienti WHERE Attivo=1");

ShowMessage(Format(L"%d ms, %d righe",
    ARRAYOFCONST((res.ElapsedMs, res.RowsAffected))));

La parte più interessante è il recupero del piano di esecuzione: non esiste una sintassi EXPLAIN universale, quindi il componente riconosce il dialetto della connessione e sceglie il comando giusto driver per driver:

DriverComando
SQL ServerSET SHOWPLAN_ALL ON
PostgreSQLEXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
MySQLEXPLAIN FORMAT=JSON
SQLiteEXPLAIN QUERY PLAN
OracleEXPLAIN PLAN FOR + DBMS_XPLAN.DISPLAY()

Per Firebird, InterBase, DB2, Informix e Access il componente ritorna semplicemente una stringa vuota invece di inventare una sintassi che potrebbe non esistere in quel dialetto. Meglio onesto che silenziosamente sbagliato.

Dal numero al disegno: TFDQueryProfilerChart

Il secondo componente, TFDQueryProfilerChart, è un TCustomControl che si aggancia all'evento OnProfileComplete del profiler e disegna tutto con GDI+: niente TeeChart, niente dipendenze esterne, solo Winapi.GDIPAPI e Winapi.GDIPOBJ, presenti in ogni edizione di RAD Studio.

Il collegamento tra i due componenti è una riga:

FDQueryProfilerChart1->Profiler = FDQueryProfiler1;

Da quel momento, ogni chiamata a Profile(), ProfileSQL() o ProfileStoredProc() fa comparire una nuova barra animata nel grafico, con:

  • Fascia KPI in alto — ultima esecuzione, media, min/max, totale query profilate;
  • Barre colorate per soglia — verde/ambra/rosso in base a due soglie configurabili (ThresholdWarningMs, ThresholdCriticalMs);
  • Animazione di crescita ease-out a 60fps quando arriva un nuovo dato;
  • Tooltip on-hover con SQL troncato, tempo, righe e dialetto;
  • Pannello di dettaglio on-click che mostra l'anteprima del piano di esecuzione.

Un dettaglio che fa la differenza: il colore ereditato

plyxSQL gestisce già più connessioni contemporaneamente in un TFDTreeExplorer, e ogni connessione ha un proprio colore identificativo nell'albero. Invece di inventare una palette scollegata, il profiler risolve il colore dello slot attivo e lo propaga al grafico:

TColor TFDQueryProfiler::ResolveConnColor(TFDConnection* AConn) const
{
    if (!FTreeExplorer || !AConn) return clNone;
    if (FTreeExplorer->ActiveConn() != AConn) return clNone;
    TConnSlot* slot = FTreeExplorer->GetActiveSlot();
    return slot ? slot->ConnColor : clNone;
}

Risultato: bordo della barra selezionata, tooltip e pannello di dettaglio si intonano automaticamente al colore già assegnato a quella connessione nell'albero, con un fallback su un accento neutro quando il profiler non è collegato a nessun TFDTreeExplorer. Un piccolo dettaglio, ma è quello che fa sembrare un componente "parte dell'app" invece che un widget incollato sopra.

#SQL #database #DataEngineering #plyxSQL #FireDAC