Prepared Statement

Sto cercando di utilizzare, per la prima volta, la tecnica dei PreparedStatement con Database SQL Server.
Guardando un po’ nella guida in linea e un po’ nell’esempio, ho scritto questo codice

Dim SQL As String
Dim prepStm As MSSQLServerPreparedStatement

    SQL = "INSERT INTO ORDFOR "
    SQL = SQL + "(OF_NumOrd, OF_Agent, OF_Dealer, OF_DatOrd, OF_DatCon, OF_NumFat, OF_DatFat, "
    SQL = SQL + " OF_ImpFat, OF_CosLog, OF_DatSca, OF_DatPag) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "
    
    prepStm = DB.Prepare(SQL)
    
    
    prepStm.BindType(0, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_INT)
    prepStm.Bind(0, OF_NumOrd)
    
    prepStm.BindType(1, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_STRING)
    prepStm.Bind(1, OF_Agent)
    
    prepStm.BindType(2, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_STRING)
    prepStm.Bind(2, OF_Dealer)
    
    prepStm.BindType(3, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DATE)
    prepStm.Bind(3, OF_DatOrd)
    
    prepStm.BindType(4, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DATE)
    prepStm.Bind(4, OF_DatCon)
    
    prepStm.BindType(5, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_INT)
    prepStm.Bind(5, OF_NumFat)
    
    prepStm.BindType(6, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DATE)
    prepStm.Bind(6, OF_DatFat)
    
    prepStm.BindType(7, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DOUBLE)
    prepStm.Bind(7, OF_ImpFat)
    
    prepStm.BindType(8, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DOUBLE)
    prepStm.Bind(8, OF_CosLog)
        
    prepStm.BindType(9, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DATE)
    prepStm.Bind(9, OF_DatSca)
    
    prepStm.BindType(10, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DATE)
    prepStm.Bind(10, OF_DatPag)
    
    
    prepStm.SQLExecute
    

Su SQLExecute il programma si blocca e non si schioda più: cosa sto sbagliando?

Grazie.

Nedi

Hello
Nedi Freguglia
the first thing that I observe
You have to make a small change in your string

SQL = "INSERT INTO ORDFOR "+_
"(OF_NumOrd, OF_Agent, OF_Dealer, OF_DatOrd, OF_DatCon, OF_NumFat, OF_DatFat, "+_
 " OF_ImpFat, OF_CosLog, OF_DatSca, OF_DatPag) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "

tell me if you solved it

regards

Raul Juarez Pulache

Hi Raul, really I don’t see any difference between your solution and mine, and in effect the result is the same: it doesn’t work.

Thank you anyway!

Antonio Rinaldi, aiuto!!

Hello
Nedi Freguglia

I do not have SQLSERVER installed on my computer, but I have tried Mysql
with its code, logically with variations such as making changes MySQL with MSSQL, long with Int
keeps the record perfectly, I attach the code as reference


  Dim DB As New MySQLCommunityServer
  DB.UserName="root"
  DB.Password="*****"
  DB.DatabaseName="bdsisarpe"
  If DB.Connect then
    
    MsgBox "conexin satisfactoria a Mysql"
    
    Dim OF_NumOrd As integer=4
    Dim OF_Agent As string="AGENT 197"
    Dim OF_Dealer As string="DEALER 197"
    Dim OF_DatOrd As string = "2018-06-03"
    Dim OF_DatCon  As string ="2018-06-03"
    Dim OF_NumFat  As integer = 45
    Dim OF_DatFat  As string ="2018-06-03"
    Dim OF_ImpFat As Double=1145.85
    Dim OF_CosLog As Double=3000.25
    Dim OF_DatSca As string = "2018-06-03"
    Dim OF_DatPag As string = "2018-06-03"
    
    Dim sql As String
    
    sql = "INSERT INTO ordfor(OF_NumOrd,OF_Agent,OF_Dealer,OF_DatOrd ,OF_DatCon,OF_NumFat,OF_DatFat,OF_ImpFat,OF_CosLog,OF_DatSca,OF_DatPag) VALUES(?,?,?,?,?,?,?,?,?,?,?) "

    Dim prepStm As PreparedSQLStatement =DB.Prepare(sql)

    prepStm.BindType(0, MySQLPreparedStatement.MYSQL_TYPE_LONG)
    prepStm.Bind(0, OF_NumOrd)
    prepStm.BindType(1, MySQLPreparedStatement.MYSQL_TYPE_STRING)
    prepStm.Bind(1, OF_Agent)
    prepStm.BindType(2,MySQLPreparedStatement.MYSQL_TYPE_STRING)
    prepStm.Bind(2, OF_Dealer)
    prepStm.BindType(3,MySQLPreparedStatement.MYSQL_TYPE_DATE)
    prepStm.Bind(3, OF_DatOrd)
    prepStm.BindType(4,MySQLPreparedStatement.MYSQL_TYPE_DATE)
    prepStm.Bind(4, OF_DatCon)
    prepStm.BindType(5, MySQLPreparedStatement.MYSQL_TYPE_LONG)
    prepStm.Bind(5, OF_NumFat)
    prepStm.BindType(6,MySQLPreparedStatement.MYSQL_TYPE_DATE)
    prepStm.Bind(6, OF_DatFat)
    prepStm.BindType(7, MySQLPreparedStatement.MYSQL_TYPE_DOUBLE)
    prepStm.Bind(7, OF_ImpFat)
    prepStm.BindType(8, MySQLPreparedStatement.MYSQL_TYPE_DOUBLE)
    prepStm.Bind(8, OF_CosLog)
    prepStm.BindType(9,MySQLPreparedStatement.MYSQL_TYPE_DATE)
    prepStm.Bind(9, OF_DatSca)
    prepStm.BindType(10,MySQLPreparedStatement.MYSQL_TYPE_DATE)
    prepStm.Bind(10, OF_DatPag)
    prepStm.SQLExecute
    
    If Not DB.Error then
      MsgBox "GRABADO CORRECTAMENTE"
    Else
      MsgBox "ERROR: NO SE PUDO GRABAR "+DB.ErrorMessage
    End If
    
    Self.cmdSalir.SetFocus
  Else
    MsgBox "Error de conexion a MySQL"
  End If

You have installed the SQL Native Client version 11.00 or higher drivers
You must first test if there is a connection to the MSSQL SERVER database
You can try only one or two fields of type string, because they can be the dates or the numbers and so you can solve more quickly
put in an error message

I hope to help you in something, comment me

regards

Raul Juarez Pulache

Thank you, Raul, for your support.
According to your advise, I tried to bind one field at a time: the first three fields are type Integer and String, and everything is OK.
The problem occurs when I add and bind a date field. I know how to deal with date field when I use the DataRecordset class or when I use a SQL statement, but with prepared statement and binding (due to my lack of experience) I don’t know how to solve the problem.

Nedi

Sorry…I mean DatabaseRecord class, not DataRecordset class…

Come formattato il campo che va in MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DATE ?

Ho provato a dargli in pasto la propriet della classe, che di tipo Date

Potresti provare con MySQLPreparedStatement.MYSQL_TYPE_STRING… dovrebbe convertirlo correttamente

Ok, adesso ci provo.
Grazie!!

Niente: non inserisce nulla, e non mi d nessuna segnalazione di nessun tipo…

prova con:
data.sqldatetime
data.sqldatetime.replace(" ", “T”)

in realt l’ideale sarebbe utilizzare datetime2 come tipo in mssql visto che questo pi compatibile (al solito MS fa i suoi standard)

Niente da fare….tutto sommato conviene utilizzare delle stored procedure al posto dei Prepared Statements.
Tu che dici, Antonio?

Se pur vero che sono strane (ad esempio non funziona la modalit a chiamata unica ma solo con il bind del value) a mio avviso se possibile vanno sempre usate.

Avevo fatto dei test ed ero riuscito a farle andare.
Magari devo fare un test pi mirato per il tuo caso:
se mi scrivi le coppie campo<->tipo e un esempio di dati che stai tentando di scrivere ti trovo la soluzione.

Grazie, Antonio!

Ecco il codice che dovrebbe eseguire degli INSERT in una tabella

[code]
Dim prepStm As MSSQLServerPreparedStatement

SQL = "INSERT INTO ORDFOR " + _
"(OF_NumOrd, OF_Agent, OF_Dealer, OF_DatOrd, OF_DatCon, OF_NumFat, OF_DatFat, " + _
" OF_ImpFat, OF_CosLog, OF_DatSca, OF_DatPag) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "

prepStm = DB.Prepare(SQL)


prepStm.BindType(0, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_INT)
prepStm.Bind(0, OF_NumOrd)

prepStm.BindType(1, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_STRING)
prepStm.Bind(1, OF_Agent)

prepStm.BindType(2, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_STRING)
prepStm.Bind(2, OF_Dealer)

prepStm.BindType(3, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DATE)
prepStm.Bind(3, OF_DatOrd)

prepStm.BindType(4, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DATE)
prepStm.Bind(4, OF_DatCon)

prepStm.BindType(5, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_INT)
prepStm.Bind(5, OF_NumFat)

prepStm.BindType(6, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DATE)
prepStm.Bind(6, OF_DatFat)

prepStm.BindType(7, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DOUBLE)
prepStm.Bind(7, OF_ImpFat)

prepStm.BindType(8, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DOUBLE)
prepStm.Bind(8, OF_CosLog)

prepStm.BindType(9, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DATE)
prepStm.Bind(9, OF_DatSca)

prepStm.BindType(10, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DATE)
prepStm.Bind(10, OF_DatPag)
prepStm.SQLExecute

[/code]

La tabella in questione ha una serie di campi che sono individuabili nella variabile SQL. La natura di tali campi visibile dai vari BindType. Il codice eseguito da una classe che ha tante propriet quanti sono i campi della tabella (e della stessa natura):tali propriet sono utilizzate nei vari Bind.

Tieni presente che alcune date (soprattutto la data pagamento OF_DatPag) potrebbero non essere valorizzate (non so come fare in questi casi).
Nei test che ho fatto comunque le date erano tutte valorizzate.

Spero di averti fornito sufficienti “indizi”: se necessiti di altre informazioni non devi far altro che dirmelo.

Grazie ancora!

Il codice che ho postato ha un ? in più nello statement SQL: c’è finito per errore. Anche con il numero corretto di parametri il risultato non cambia.

Ok.
Ti chiedevo i tipi originali (nel db) e il tipo di variabile che inserisci perch il problema potrebbe essere quello.

E dovendo creare una tabella di test per replicare devo sapere la definizione.
Diciamo che da quello che hai postato:
OF_NumOrd, OF_NumFat ->INTEGER
OF_Agent, OF_Dealer -> VARCHAR(200)
OF_DatOrd, OF_DatCon, OF_DatFat, OF_DatSca, OF_DatPag -> DATETIME (null o NOT NULL)
OF_ImpFat, OF_CosLog ->DOUBLE

Da cui potrei creare una tabella con:
CREATE TABLE ORDFOR (OF_NumOrd INTEGER, OF_Agent VARCHAR(200), OF_Dealer VARCHAR(200), OF_DatOrd DATETIME, OF_DatCon DATETIME, OF_NumFat INTEGER, OF_DatFat DATETIME, OF_ImpFat DOUBLE, OF_CosLog DOUBLE, OF_DatSca DATETIME, OF_DatPag DATETIME)

Corretto?

Le variabili per l’esempio:
Dim OF_NumOrd as Integer=1
Dim OF_Agent as string=“Agente”
Dim OF_Dealer as string=“Venditore”
Dim OF_DatOrd as new Date
Dim OF_DatCon as new Date
Dim OF_NumFat as integer=1
Dim OF_DatFat as new Date
Dim OF_ImpFat as double=1000.0
Dim OF_CosLog as double=200.25
Dim OF_DatSca as new Date
Dim OF_DatPag as new Date

OK?
Se mi indichi quali campi sono NULLABILI posso verificare anche quel caso (ad esempio penso la OF_DatPag)

I due campi String sono VarChar(50). Tutti gli altri vanno bene. Nel DB l’unico campo che non pu essere Null OF_NumOrd, in quanto primary key.
Nella realt vengono tutti valorizzati sempre, tranne OF_DatPag.

Nelle istruzioni di Bind utilizzo delle propriet della classe che hanno stesso nome e tipologia dei campi del DB.
Nel DB i campi data sono di tipo Date (non DateTime)

Questo funziona (almeno da me):

//Non ho inserito il NumOrd perch definito come identity, ma non  quello il problema
dim p as PreparedSQLStatement=mDB.Prepare("insert into ORDFOR (OF_Agent, OF_Dealer, OF_DatOrd, OF_DatCon, OF_NumFat, OF_DatFat, OF_ImpFat, OF_CosLog, OF_DatSca, OF_DatPag) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")

//Uso la sintassi con 3 parametri per far prima, di solito in realt uso prima il bindtype e poi la execute o select con i parametri
//ma non funziona nel caso di MSSQL
p.Bind(0, OF_Agent, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_STRING)
p.Bind(1, OF_Dealer, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_STRING)
p.Bind(2, OF_DatOrd, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_STRING)
p.Bind(3, OF_DatCon, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_STRING)
p.Bind(4, OF_NumFat, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_INT)
p.Bind(5, OF_DatFat, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_STRING)
p.Bind(6, OF_ImpFat, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DOUBLE)
p.Bind(7, OF_CosLog, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_DOUBLE)
p.Bind(8, OF_DatSca, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_STRING)
p.Bind(9, OF_DatPag, MSSQLServerPreparedStatement.MSSQLSERVER_TYPE_STRING)
p.SQLExecute