how to use access VBA to store SQL output as XML - ms-access

My apologies for the description, I have no idea how to name it properly
I have a few stored procedures (running on SQL2000) that provide me XML data as output. This all works fine and as expected, and I am using a VB module within my DTS to export and store the data. The reduced version of this file is as follows
set objStream = CreateObject( "ADODB.Stream" )
set objXML = CreateObject( "MSXML2.DOMDocument" )
set objConn = CreateObject( "ADODB.Connection" )
objConn.ConnectionTimeout = 3600
objConn.CommandTimeOut = 0
ObjConn.open(DTSGlobalVariables("ConnStringConso").Value)
set objComm = CreateObject( "ADODB.Command" )
objComm.ActiveConnection = objConn
objComm.CommandType = adCmdStoredProc
'Create the Stream object
set objStream = CreateObject( "ADODB.Stream" )
objStream.Open
objComm.Properties( "Output Stream" ) = objStream
' Execute the command
objComm.CommandText = "my_stored_procedure"
objComm.CommandTimeout = 3600
objComm.Execute ,, adExecuteStream
' Read the info returned adding the header and footer info
objStream.Position = 0
objXML.LoadXML("<?xml version='1.0'?>" & objStream.ReadText)
' Create the output XML file
xmlfile = filePath & "myfile.xml"
objXML.save( xmlfile )
So basically what this does is call the procedure, store the output in a stream and save the file, fairly straightforward and up till here no issue.
However, I would also need to be able to do this from my access front end, with VBA. So calling the procedure, wrapping the content and saving it as an XML file. Unfortunately my VBA knowledge is a bit rusty...
This is what I currently have :
Dim cnn As ADODB.Connection
Dim cmd As New ADODB.Command, rs As New ADODB.Recordset
Set cnn = New ADODB.Connection
cnn.ConnectionString = "DRIVER=SQL Server;SERVER=myserver;DATABASE=myDatabase;uid=myID;pwd=myPW;Trusted_Connection=Yes"
cnn.Open cnn.ConnectionString
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = cnn
.CommandType = adCmdStoredProc
.CommandText = "my_stored_procedure"
End With
rs.CursorType = adOpenStatic
rs.CursorLocation = adUseClient
rs.LockType = adLockOptimistic
rs.Open cmd
Debug.Print rs(0)
so far so good, I can open the procedure, I get data returned, but that's where my luck ends. The returned data seems to be limited to a certain number of characters (around 2000) and I'm struggling to save it as I want.
I tried below for quick and dirty test, but it appears to screw up my XML (all my attributes are suddenly double-double quoted) and as stated only a part of the content is exported, so any advice on how to do it properly would be highly appreciated
Dim myFile As String
myFile = "d:\output.xml"
Open myFile For Output As #1
Write #1, rs(0)
Close #1

Never mind, I found it myself in the meantime. I had 2 issues, the VBA ADODB works different as the VB variant, and as I was using FOR XML on my SQL Query the output apperantly was chopped in different rows. Hence why I only had partial output. Fiddling a bit with the streaming part in VBA and going through all records made it work. Not too sure this is the most optimal way so if there are ways to improve I'd be interested to know.
Dim cmd As New ADODB.Command, rs As New ADODB.Recordset
Dim cnn As ADODB.Connection
Set cnn = New ADODB.Connection
cnn.ConnectionString = "DRIVER=SQL Server;SERVER=myServer;DATABASE=myDB;uid=myID;pwd=myPW;Trusted_Connection=Yes"
cnn.Open cnn.ConnectionString
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = cnn
.CommandType = adCmdStoredProc
.CommandText = myProc
End With
rs.CursorType = adOpenStatic
rs.CursorLocation = adUseClient
rs.LockType = adLockOptimistic
rs.Open cmd
Dim myXML As Variant
If Not (rs.EOF And rs.BOF) Then
rs.MoveFirst
Do Until rs.EOF = True
myXML = myXML & rs.Fields(0)
rs.MoveNext
Loop
End If
'Create the Stream object
Set objStream = CreateObject("ADODB.Stream")
With objStream
.Type = 2 'Text
.Charset = "utf-8"
.Open
.WriteText myXML
.SaveToFile (filePath & myXMLFile)
.Close
End With

Related

VBS DTEXEC - SSIS Package fails to fully execute before continuing on

I have a vbs script that's failing to finish loading a file before moving on to the next steps. I've been using this code for 2+ years so this is likely due to my poor code and error handling - If the SSIS package fails to fully load, the procedure should kick out and alert me - Can someone point me in the right direction to make sure this package fully loads or if it fails, truncate the stage table and try again?
The file can range from 50mb to 1.2Gb
'******************************
Sub ReloadTable(strTableName)
'******************************
Dim wsh
Set wsh = CreateObject("WScript.Shell")
Dim waitOnReturn
waitOnReturn = True
Dim windowStyle
windowStyle = 0
Dim errorCode
Dim DTEXECStatus
'Truncate the stage table
ExecOnSQL "TRUNCATE TABLE essstage." & strTableName
'Run the SSIS package and wait until complete
errorCode = wsh.Run("dtexec /File ""\\server.dev.local\Data\SSIS SQL16\" & strTableName & ".dtsx"" ", windowStyle, waitOnReturn)
If errorCode = 0 Then
DTEXECStatus = "Success! " & strTableName
'MsgBox "Success! " & strTableName
Else
'Should exit the sub if this fails and notify me
DTEXECStatus = "FAILED!! " & strTableName
Create_NOTICE_Email
MsgBox "Failed! " & strTableName
'It'd be better if this repeated the steps to clear/attempt to reload again but who knows how to do that
Exit Sub
'ML: Added this END to the script to see if it'll stop erroring out
End If
End Sub
'******************************
Sub ExecOnSQL(cmdTxt)
'******************************
Dim strConnSQL
strConnSQL = "Provider=SQLOLEDB; Server=SQLSERVER.dev.LOCAL; Database=goldmouse; Trusted_Connection=Yes"
'Open the connection to the database
Dim cn
Set cn = CreateObject("ADODB.Connection")
cn.Open strConnSQL
'Set the command
Dim cmd
Set cmd = CreateObject("ADODB.Command")
Set cmd.ActiveConnection = cn
'Set the record Set
Dim rs
Set rs = CreateObject("ADODB.recordSet")
'Prepare the command
cmd.CommandText = cmdTxt
cmd.CommandType = 1 'adCmdText
cmd.CommandTimeout = 3000 '50 minutes
'cmd.CommandType = 4 'adCmdStoredProc
'Execute the command
Set rs = cmd.Execute
Set cmd = Nothing
'Close connections
cn.Close
Set cn = Nothing
End Sub

MSAccess: Run Stored Proc Asynchronously w/Return - Syntax?

I have had good success in past running single threaded SPs, waiting for a "0" or "-1" reply to indicate success, using:
Set cnn = New ADODB.Connection
cnn.CursorLocation = adUseClient
cnn.ConnectionString = "driver={SQL Server};server=" & TempVars!my_ip & ";Trusted_Connection=no;Database=" & TempVars!my_Database & ";UID=username;PWD=password"
cnn.CommandTimeout = 0
cnn.Open
strSQL = "ExportToCSVZip 'myTable', '\\192.168.242.147\InventoryProcessing\Exports\', 'ProdCIVProcess', 'Y';"
Set rs = cnn.Execute(strSQL)
'SP Result -1 = Success, 0 = Fail
If rs.Fields(0) = -1 Then
msgbox "Done"
Else
msgbox "Fail"
End If
I can run this asynchronously using:
cnn.Execute strSQL, adExecuteNoRecords, adAsyncExecute
But I am unclear the proper syntax in this form to determine the Return flag. My attempts have returned an 'ordinal' error.
Suggestions?
Depending on your exact config, you can return parameters quite easily.
Assume you have the following SP:
CREATE PROCEDURE TestSP
#Param1 INT OUT
AS
WAITFOR DELAY '00:00:03';
SET #Param1 = 5;
Then, declare globally in your module:
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
And then, in your function:
Set cnn = New ADODB.Connection
cnn.Open = "Some connectionstring"
Set cmd = New ADODB.Command
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "TestSP"
Dim p As ADODB.Parameter
Set p = cmd.CreateParameter("#Param1", adInteger, adParamOutput, 8)
cmd.Parameters.Append p
Set cmd.ActiveConnection = conn
cmd.Execute Options:=adAsyncExecute
Then, in a separate function, test if the command is done and if so return the value
If cmd.State <> adStateExecuting Then
returnValue = cmd.Parameters("#Param1").Value 'Returns 5 when done
End If
'Because of the global scope, cleanup is required
conn.Close
Set conn = Nothing
Set cmd = Nothing

Exporting data from SCADA system

I am trying to create VBscript to export process data from a SCADA system (WinCC RT Professional) to periodically archive all process variables. The data are stored in SQL table that can be accessed through a connectivity pack. I managed to make the script working when exporting one tag (process variable), but I would like to loop over all tags in the system (about 60), collect them in another recordset and then all data from this recordset save in one csv-file. I have created RecSet that collects all variables (fields) of one tag (Time, Process Variable etc.), I only need values from Field 4 (the same field for all tags). I would then like to copy this field in another recordset - RecSetColl which collects all required data (Field 4) from all tags and finally save them in the CSV file. Thank you very much for any help.
Sub DataExport()
Dim fso 'FileSystemObject
Dim f 'File
Dim ts 'TextStream
Dim path 'Path
Dim ArchiveDate 'Archive date
'Name of CSV-file
ArchiveDate = ArchiveDate & Now
ArchiveDate = Replace(ArchiveDate,"/","")
ArchiveDate = Replace(ArchiveDate," ","")
ArchiveDate = Replace(ArchiveDate,":","")
ArchiveDate = "MDF_" & ArchiveDate
'Path to the csv-file
path = "D:\Historical_data\" & ArchiveDate & ".csv"
'Create Filesystemobject and CSV-file if not exists:
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(path) Then
fso.CreateTextFile(path)
Else
MsgBox "File already exists!"
Exit Sub
End If
'Create object and open it for writing
Set f = fso.GetFile(path)
Set ts = f.OpenAsTextStream(2,-2)
ts.WriteLine("Tag-Name;ValueID;Date/Time;Process-Value") 'Header
'Generate String for the CSV-Filename
Dim Pro 'Provider
Dim DSN 'Data Source Name
Dim DS 'Data Source
Dim ConnString 'Connection String
Dim MachineNameRT 'Name of the PC from WinCC-RT
Dim DSNRT 'Data Source Name from WinnCC-RT
Dim Conn 'Connection to ADODB
Dim RecSet 'RecordSet
Dim RecSetColl 'RecordSet storing data to be saved to the CSV-file
Dim Command 'Query
Dim CommandText 'Command-Text
Dim i
'Read the name of the PC-Station and the DSN-Name from WinCC-RT
Set MachineNameRT = HMIRuntime.Tags("#LocalMachineName")
Set DSNRT = HMIRuntime.Tags("#DatasourceNameRT")
'Preparing the Connection-String
Pro = "Provider=WinCCOLEDBProvider.1;" 'First instance of WinCCOLEDB
DSN = "Catalog=" & DSNRT.Read & ";" 'Name of Runtime-Database
DS = "Data Source=" & MachineNameRT.Read & "\WinCC" 'Data Source
'Build the complete String:
ConnString = Pro + DSN + DS
'Make Connection
Set Conn = CreateObject("ADODB.Connection")
Conn.ConnectionString = ConnString
Conn.CursorLocation = 3
Conn.open
Set RecSetColl = CreateObject("ADODB.Recordset")
With RecSetColl.Fields
.Append "Time1", adChar
.Append "AHU_RUN", adChar
.Append "Time2", adChar
.Append "TT01", adChar
.Append "TT02", adChar
End With
For i = 0 To 4
Set RecSet = CreateObject("ADODB.Recordset")
Set Command = CreateObject("ADODB.Command")
Command.CommandType = 1
Set Command.ActiveConnection = Conn
'Building the complete string
CommandText = "Tag:R," & i & ",'0000-00-00 12:00:00.000','0000-00-00 00:00:00.000'"
Command.CommandText = CommandText
Set RecSet = Command.Execute
RecSet.MoveFirst
RecSetColl.Fields(i) = RecSet.Fields(4) 'RecSet.Fields(4) stores a proces value
RecSet.Close
Set RecSet = Nothing
Set Command = Nothing
Next
'Writing recordsets to CSV-file
Do While Not RecSetColl.EOF
ts.WriteLine (RecSetColl.Fields(0).Value & ";" & RecSetColl.Fields(1).Value & ";" & RecSetColl.Fields(2).Value & ";" & RecSetColl.Fields(3).Value & ";" & RecSetColl.Fields(4).Value & ";" & RecSetColl.Fields(5).Value)
RecSetColl.MoveNext
Loop
RecSetColl.Close
Set RecSetColl = Nothing
Conn.close
Set Conn = Nothing
ts.Close
Set fso = Nothing
Set f = Nothing
Set ts = Nothing
End Sub
I do not really know whats not working, but a guess;
Does ValueID = 0 , (the "i" in the "for 0 to 4" ) exist in your project?
In the table "Archive" you will find the valid ValueIDs, starts with "1" in all my projects. It's simple to see in SQL Management Studio, perhaps sometimes 0 exist.
To get all the values exported, query the "Archive" table first and then ask for data in a loop using whatever ValueID's is returned.
//PerD

Run Time Error "424" Object Required / Ms Access VBA ./ Objects are declared but still the error Could some one spot the error?

Private Sub method3_Click()
Dim conn1 As ADODB.Connection
Dim recSet As ADODB.Recordset
mySQL = "Select * from Contact"
Set conn1 = New ADODB.Connection
conn1.Provider = "Microsoft.ACE.OLEDB.12.0"
'ERROR WHEN PROGRAM REACHES THE LINE BELOW
conn1.Open (Server.Mappath("G:\Data\StudentDB.accDB"))
Set recSet = New ADODB.Recordset
recSet.Open mySQL, conn1, adOpenDynamic, adLockOptimistic
mobile = recSet.Field(3)
recSet.Close
conn1.Close
Set conn = Nothing
Set recSet = Nothing
End Sub
Server is not defined at that exact line.
You can use SET Conn1 = CurrentProject.Connection to avoid having to create a new connection from scratch.

Reading image from MS-Access database in Classic ASP

I am trying to read JPG images from MS-Access database using the following code in classic ASP:
Response.Expires = 0
Response.Buffer = TRUE
Response.Clear
Response.ContentType = "image/jpg"
Set cn = Server.CreateObject("ADODB.Connection")
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & Server.MapPath("/database/database.mdb")
sqlString = "Select * from tblBusinessImages where fldID = " & request.querystring("id")
Set rs = cn.Execute(sqlString)
Response.BinaryWrite rs("fldImageData")
Response.End
But I keep getting an error telling that the browser can't read or display the image.
The database field 'tblBusinessImages' is an OLE field, and the image is saved into it by copy-paste, only for testing purpose at this time (could this be a wrong way?)
Now I know that MS-Access saves extra data in the BLOB object (as MSDN says here:
If any extraneous information is contained in the BLOB data, this will
be passed by this script, and the image will not display properly.
This becomes important when you realize that most methods of placing
images into BLOB fields place extra information in the form of headers
with the image. Examples of this are Microsoft Access and Microsoft
Visual FoxPro. Both of these applications save OLE headers in the BLOB
field along with the actual binary data.
)
My question is how do I read the RAW image data from a BLOB without the extra data/headers that MS-Access saves?
Thanks.
After a day of work I realized what the problem was: The problem was in the way the picture was saved to the database (manually).
In order to save images to database, the following code should be used:
Dim fileName
Dim conn
Dim rsTemp
Dim fldID
Dim sSQL
Dim mystream
Set mystream = Server.CreateObject("ADODB.Stream")
mystream.Type = 1
mystream.Open
mystream.LoadFromFile "D:\Desktop\My Downloads\compose1.jpg"
Set conn = Server.CreateObject("ADODB.Connection")
Set rsTemp = Server.CreateObject("ADODB.Recordset")
conn.Open "DRIVER=Microsoft Access Driver (*.mdb);DBQ=" & Server.MapPath("/database/database.mdb")
sSQL = "Select fldImageData from tblBusinessImages where fldID = 1;"
rsTemp.Open sSQL, conn, 3, 3
rsTemp.Fields("fldImageData").AppendChunk mystream.Read
rsTemp.Update
rsTemp.Close
set mystream = nothing
And in order to read an image from MS-Access database, this code should be used:
Dim conn
Dim rsTemp
Dim sSQL
Dim fldID
fldID = Request.QueryString("id")
If Not fldID = "" And IsNumeric(fldID) Then
Set conn = Server.CreateObject("ADODB.Connection")
Set rsTemp = Server.CreateObject("ADODB.Recordset")
conn.Open "DRIVER=Microsoft Access Driver (*.mdb);DBQ=" & Server.MapPath("/database/database.mdb")
sSQL = "Select * from tblBusinessImages where fldID = " & request.querystring("id")
rsTemp.Open sSQL, conn, 3, 3
If Not rsTemp.EOF Then
Response.ContentType = "image/jpeg"
Response.BinaryWrite rsTemp("fldImageData")
Else
Response.Write("File could not be found")
End If
rsTemp.Close
conn.Close
Set rsTemp = Nothing
Set conn = Nothing
Else
Response.Write("File could not be found")
End If
This way the image data will be saved as Long Binary Data in the OLE field in the database. When read, it will be posted to the browser as a readable image data.