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.
Related
I am working on a project where the company still has everything in lotus notes and we're starting redesign the system so they no longer run on Lotus.
Now, I am just trying to import the Lotus tables in an MS Access Database but keep getting the error "Numeric Overflow". Does anyone know how to handle this?
The table has 196 columns and 846 rows. Currently, I have named a range in the lotus table. However, ideally we would be able to just name the range we want to import so:
"SELECT * INTO PRNTDATM FROM [a:a1..a:a8100]"
Full error:
Run-time error '-2147467259(800004005)' Numeric Field overflow
Private Sub Command0_Click()
Dim CombLoop As Integer
Dim LotusCn As Object
Dim rsLotus As Object
Dim strSql, CombFileName, GotoRange As String
Set LotusCn = CreateObject("ADODB.Connection")
Set rsLotus = CreateObject("ADODB.Recordset")
LotusCn.Open "Provider=Microsoft.Jet.OLEDB.4.0; Data Source= K:\GEVS04\NUMBDATM.WK3; Extended Properties=Lotus WK3;"
strSql = "Select * INTO PRNTDATM FROM phil"
rsLotus.Open strSql, LotusCn
LotusCn.Close
Set rsLotus = Nothing
Set LotusCn = Nothing
End Sub
Since this Post i have been working on it and had some improvements i can now read and import some test data to the tables. Found appending worked better than importing whole new table so will have to try that route. Doing this seems to have fixed the overflow issue because i now have the table structure itself already in place as there are only about 5 Table structures that should work fine for this code.
The code is now:
Dim CombLoop As Integer
Dim LotusCn As Object
Dim rsLotus As Object
Dim strSql As String
Dim rs As DAO.Recordset
Set LotusCn = CreateObject("ADODB.Connection")
Set rsLotus = CreateObject("ADODB.Recordset")
LotusCn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=C:\Users\germany5.PLIMSOLL\Desktop\TEST.WK4;" & _
"Extended Properties=Lotus WK4;"
strSql = "SELECT * FROM [a1..C3];"
rsLotus.Open strSql, LotusCn
Set rs = CurrentDb.OpenRecordset("Select * From NICHDATMGECO20;")
If Not (rsLotus.EOF And rsLotus.BOF) Then
FindRecordCount = rsLotus.RecordCount
rsLotus.MoveFirst
Do Until rsLotus.EOF = True
Field1 = rsLotus![Reg. Number]
Field3 = rsLotus![Sales / Tot.Assets]
Field2 = rsLotus![Company Name]
rs.AddNew
rs![Reg. Number] = Field1
rs![Company Name] = Field2
rs.Update
rsLotus.MoveNext
Loop
End If
LotusCn.Close
Set rsLotus = Nothing
Set LotusCn = Nothing
rs.Close
Just to let you know the problem has been solved and above is the end result of the code which works fine for me. I did need to reference Lotus 123 in Tools just in case anyone wants to replicate what Ive done here.
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
I'm developing a VB Script for WinCC RunTime on a SIMATIC PC station to export the historical data of my project once a month. I'm setting up an ADO connection and querying the results into a recordset that I'm printing to a csv. I'm having several problems:
The recordset returns a ValueID, I want to be able to find the tagname that corresponds to it and write it to the csv.
I am limited to 20 tags per query, but I want to export 30 tags.
Running a for loop of the query for each tag produces nothing.
My code currently looks like this:
Dim fso
Dim f
Dim ts
Dim path
Dim TimeStamp
Dim Pro
Dim DSN
Dim DS
Dim ConnString
Dim MachineNameRT
Dim DSNRT
Dim Conn
Dim RecSet
Dim Command
Dim CommandText
TimeStamp = localDateFormat(Now)
path = "C:\Logs\Test1_" & TimeStamp & ".csv"
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(path) Then
fso.CreateTextFile(path)
Else
MsgBox "File already exist:" & vbCrLf & path
Exit Sub
End If
Set f = fso.GetFile(path)
Set ts = f.OpenAsTextStream(2,-2)
Set MachineNameRT = HMIRuntime.Tags("#LocalMachineName")
Set DSNRT = HMIRuntime.Tags("#DatasourceNameRT")
Pro="Provider=WinCCOLEDBProvider.1;"
DSN="Catalog=" & DSNRT.Read & ";"
DS= "Data Source=" & MachineNameRT.Read & "\WinCC"
ConnString = Pro + DSN + DS
Set Conn = CreateObject("ADODB.Connection")
Conn.ConnectionString = ConnString
Conn.CursorLocation = 3
Conn.open
Set Command = CreateObject("ADODB.Command")
Command.CommandType = 1
Set Command.ActiveConnection = Conn
ts.WriteLine ("Tag-Name;ValueID;Date/Time;Process-Value")
CommandText="Tag:R,'Data_Log\TempTran','0000-01-00 00:00:00.000','0000-00-00 00:00:00.000'"
Command.CommandText=CommandText
Set RecSet = Command.Execute
RecSet.MoveFirst
Do While Not RecSet.EOF
ts.WriteLine ("TempTran;" & RecSet.Fields("ValueID").Value & ";" & RecSet.Fields("TimeStamp").Value & ";" & RecSet.Fields("RealValue").Value)
RecSet.MoveNext
Loop
ts.Close
RecSet.Close
Set RecSet=Nothing
Set Command = Nothing
Conn.Close
Set Conn = Nothing
Set fso = Nothing
Set f = Nothing
Set ts = Nothing
What I need as an end result is a CSV file that displays like this
Tag-Name;ValueID;Date/Time;Process-Value;
TempTran;1;dd/mm/yyyy hh:mm:ss;xxx.xxx;
TempTran;1;dd/mm/yyyy hh:mm:ss;xxx.xxx;
PresTran;2;dd/mm/yyyy hh:mm:ss;xxx.xxx;
.
.
.
.
LimitSwt;30;dd/mm/yyyy hh:mm:ss;xxx.xxx;
LimitSwt;30;dd/mm/yyyy hh:mm:ss;xxx.xxx;
LimitSwt;30;dd/mm/yyyy hh:mm:ss;xxx.xxx;
Q1:
The ValueID and tagname is in the Table "Archive" if the database is linked to connectivity pack.
SELECT [ValueID]
,[ValueName]
FROM [CC_ExternalBrowsing].[dbo].[Archive]
Otherwise you can find the valueId in the CS database
Runtime is in this case "CC_GruppLar_15_05_06_10_35_08R", its the last 'R' that indicate "runtime", remove this and you are in the construction database(CS):
Varname = the given name
procvarname= the tag that is archived.
TLGTAGID = The ValueID
SELECT [VARNAME]
,[PROCVARNAME]
,[TLGTAGID]
FROM [CC_GruppLar_15_05_06_10_35_08].[dbo].[PDE#TAGs]
Q3:
perhaps this note about months in the fine help can help? or try to verify using that there is data present for this tag. I think its a good idea to test the SQL statements using the given tool "Microsoft SQL Manager Studio", that's faster then using excel...
Note
Enter a relative period you want to query in a linked archive database using the following format:
0000-00-DD hh:mm:ss.msc
If you indicate the time frame in months, the content can be faulty, because a month can have 28 to 31 days.
Example for reference:
Exporting Archive Data with the Aid of the SIMATIC WinCC/Connectivity Pack (OLE DB Provider)
https://support.industry.siemens.com/cs/se/en/view/38132261
So I navigated to the following MSDN Resource Page that addresses how to use ADO objects. My problem is that I cannot get it to work.
What I am trying to do is open a CSV file and read it line-by-line, then create SQL INSERT statements to insert the records into an existing Table in Access 2010. I have tried to find an easier method of doing this, but this appears to be my only option. doing this with the included tools, but so far, I haven't had any luck.
The main issue here is that I have CSV files with inconsistent headings. I want to import 5 files into the same table, but each file will be different depending on which fields contained data. Those fields with no data in them were ignored during the extract. This is why I can't use something like DoCmd.TransferText.
So, now I need to create a script that will open the text file, read the headers in the first line and create a SQL INSERT statement dependent on the configuration of that particular file.
I have a feeling that I have a good handle on how to appraoch the issue, but no matter what I try, I can't seem to get things working using ADO.
Could anyone explain how I can achieve this? My sticking point is getting the Access DB to receive information from the CSV files via ADO.
Instead of reading the CSV file line-by-line, then doing something with each line, I think you should open the file as an ADO recordset. And open a DAO recordset for your Access destination table.
You can then iterate through the fields in each row of the ADO recordset and add their values into a new row of the DAO recordset. As long as the destination table includes fields with the same names and compatible data types as the CSV fields, this can be fairly smooth.
Public Sub Addikt()
#If ProjectStatus = "DEV" Then
' needs reference for Microsoft ActiveX Data Objects
Dim cn As ADODB.Connection
Dim fld As ADODB.Field
Dim rs As ADODB.Recordset
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
#Else ' assume PROD
Const adCmdText As Long = 1
Const adLockReadOnly As Long = 1
Const adOpenForwardOnly As Long = 0
Dim cn As Object
Dim fld As Object
Dim rs As Object
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
#End If
Const cstrDestination As String = "tblMaster"
Const cstrFile As String = "temp.csv"
Const cstrFolder As String = "C:\share\Access"
Dim db As DAO.Database
Dim rsDao As DAO.Recordset
Dim strConnectionString As String
Dim strName As String
Dim strSelect As String
strConnectionString = "Provider=" & _
CurrentProject.Connection.Provider & _
";Data Source=" & cstrFolder & Chr(92) & _
";Extended Properties='text;HDR=YES;FMT=Delimited'"
'Debug.Print strConnectionString
cn.Open strConnectionString
strSelect = "SELECT * FROM " & cstrFile
rs.Open strSelect, cn, adOpenForwardOnly, _
adLockReadOnly, adCmdText
Set db = CurrentDb
Set rsDao = db.OpenRecordset(cstrDestination, _
dbOpenTable, dbAppendOnly + dbFailOnError)
Do While Not rs.EOF
rsDao.AddNew
For Each fld In rs.Fields
strName = fld.Name
rsDao.Fields(strName) = rs.Fields(strName).value
Next fld
rsDao.Update
rs.MoveNext
Loop
rsDao.Close
Set rsDao = Nothing
Set db = Nothing
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
This is the Declarations section of the module where I saved that procedure:
Option Compare Database
Option Explicit
#Const ProjectStatus = "DEV" '"DEV" or "PROD"
Change the values for these constants to test it on your system:
Const cstrDestination As String = "tblMaster"
Const cstrFile As String = "temp.csv"
Const cstrFolder As String = "C:\share\Access"
Note the folder name does not include a trailing backslash.
You will want to adapt that procedure to pass the file name as a parameter instead of leaving it as a constant. And, if your CSV files are stored in more than one directory, you will want to pass the folder name as a parameter, too.
Hopefully showing you how to do it for one file will be enough and you can then take it from here to handle all your CSV files. Also consider adding error handling.
I think the previous answer is unnecessarily complicated. All you need to do it send an XMLHTTP request. That fetches the CSV data as a string, which can then be parsed into a table.
I've posted a VBA subroutine that does that in an answer to a similar question. Documentation of where I found the techniques is in the code comments. I've run it in Access 2019, and it works.
This code:
db = "C:\Dokumente und Einstellungen\hom\Anwendungsdaten\BayWotch4\Neuer Ordner\baywotch.db5"
TextExportFile = "C:\Dokumente und Einstellungen\hom\Anwendungsdaten\BayWotch4\Neuer Ordner\Exp.txt"
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open _
"Provider = Microsoft.Jet.OLEDB.4.0; " & _
"Data Source =" & db
strSQL = "SELECT * FROM tblAuction1"
rs.Open strSQL, cn, 3, 3
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.CreateTextFile(TextExportFile, True, True)
a = rs.GetString
f.WriteLine a
f.Close
generates a tab delimited file, however it is not suitable for importing into mysql. I would like it to generate a file similar to a file produced by an access macro, which can be seen here:
http://www.yousendit.com/download/TTZtWmdsT01kMnVGa1E9PQ
The file produced by the vbscript is here:
http://www.yousendit.com/download/TTZtWmdsT00wVWtLSkE9PQ
I would also like to know why the file sizes differ by 50k or so.
Edit: The result from the vbscript file uses newline characters that are not recognized by notepad, so the above looks substantially messier when viewed. The macro does not seem to be exporting the html code, which explains why it is a smaller file, however the vbscript does not appear to be tab delimited, as it will not import into mysql.
Edit: the files look ok under a linux system, so it could be something to do with windows handling. However it is still not correct.
Both files contain what looks like tab-delimited data as well as HTML code (generated by some MS Office app, by the looks of it). Does tblAuction1 store any OLE Objects? Perhaps when you're exporting those objects it's exporting the file contents?
It looks like an encoding issue to me. I see that you are passing the Unicode parameter when you create the text file, but there is clearly an encoding difference between the two files.
What is the goal of this project? What is the purpose of creating the file? If you are just looking to move data from Access to MySQL, why not do it directly with something like this
Const Access = "Provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=False;Data Source=C:\Dokumente und Einstellungen\hom\Anwendungsdaten\BayWotch4\Neuer Ordner\baywotch.db5"
Const SQLServer = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Data Source=.\SQLEXPRESS"
Dim arrFields
Set SQLConn = CreateObject("ADODB.Connection")
WITH SQLConn
.ConnectionString = SQLServer
.Open
End WITH
Set AccessConn = CreateObject("ADODB.Connection")
WITH AccessConn
.ConnectionString = Access
.Open
End WITH
Set SQLRS = CreateObject("ADODB.Recordset")
WITH SQLRS
.CursorType = 3
.LockType = 3
End WITH
Set AccessRS = CreateObject("ADODB.Recordset")
WITH AccessRS
.ActiveConnection = AccessConn
.CursorType = 3
.LockType = 3
End WITH
strSQL = "SELECT * FROM tblAuction1"
AccessRS.Open strSQL
If AccessRS.RecordCount <> 0 Then
AccessRS.MoveFirst
ReDim arrFields(AccessRS.Fields.Count)
Do Until AccessRS.BOF OR AccessRS.EOF
For i = 0 To AccessRS.Fields.Count - 1
If AccessRS.Fields(i).Type = 202 Then
arrFields(i) = Chr(39) & AccessRS.Fields(i).Value & Chr(39)
Else
arrFields(i) = AccessRS.Fields(i).Value
End If
Next
strSQL1 = "INSERT INTO {Table in mySQL} VALUES("
For j = 1 To UBound(arrFields) - 2
strSQL1 = strSQL1 & arrFields(j) & ","
Next
strSQL1 = strSQL1 & arrFields(UBound(arrFields) - 1) & ")"
SQLRS = SQLConn.Execute(strSQL1)
AccessRS.MoveNext
Loop
Else
MsgBox "No records found"
End If
This will add all of the records returned by the recordset to a table in an SQLExpress database,it should not be difficult to tweak to your needs (if your needs are transferring data from one database to another).