I'm trying to read a .DBF data base using VB.NET... the code is working until I reach a column on one of the tables that is supposed to be Decimal but it is instead filled with asterisks.
The connection string and reader I'm using go like this:
Using SDBconnection As New OleDbConnection("User ID=;" & _
"DSN=;" & _
"Cache Authentication=False;" & _
"Data Source=""" & TextBox_DBLoc.Text & """;" & _
"Provider=""VFPOLEDB"";" & _
"Collating Sequence=MACHINE;" & _
"Mask Password=False;" & _
"persist security info=False;" & _
"Mode=Share Deny None;" & _
"Extended Properties=;" & _
"Encrypt Password=False")
Dim oleReader As OleDbDataReader = New OleDbCommand("Select * from " & table, SDBconnection).ExecuteReader()
Is there some way to evaluate when the data type does not correspond and then to a cast or something like that?
The table is readable in other DBF reader software and no error is showed when read. How can I do the same?
EDIT:
The error message thrown by my code when it reaches the column with asterisks is this:
The provider could not determine the Decimal value. For example, the row was just created, the default for the Decimal column was not available, and the consumer had not yet set a new Decimal value.
There is a problem with Visual Foxpro that apparently allows the user to enter a overflowed value in numeric fields which doesn't seem to cause an issue in Visual Foxpro. However, it does cause problems when accessing the data using anything other than Visual Foxpro because it violates the settings for this field. VFPOLEDB returns these values as asterisks.
As a workaround, you could try the following query:
SELECT VAL(STR(SaleAmt)) as SaleAmt FROM MyTable
This converts the decimal column (SaleAmt) to a string and then back to a numeric value.
You also can check your data for overflowed values and modify the dbf table structure to solve this problem.
This link explains this problem
Related
I built an Access database to contain information regarding parts that we use to create schematics. There is one table that contain "basic" information, like "unique part ID" ("TUPID"), links to datasheets and so on - and the "Partition" further information is stored.
Furthermore there are several tables (this is "Partition") that contain information on the part itself: one table for resistors, one for connectors, one for power-ICs and so on. Each table has many fields different from other tables, but there are fields that exist on each table, eg. "Manufacturer", "Symbol", "Package" and "Height".
Now I have a split form ("10_Change_BaseInformation") that shows the "basic information", so when I select one row in the database-part of the form, the data is loaded into textboxes and can be edited. Additionally I want to see the information from the "Partition"-table in this form, so I wrote this:
Private Sub Form_Click()
Dim SelectedPartition As String: SelectedPartition = Forms![10_Change_BaseInformation]![Text25]
'Field "Text25" contains the TUPID
Dim SQLStatement As String
SQLStatement = "SELECT " & SelectedPartition & ".TUPID, " & SelectedPartition & ".[Mfg]" & vbCr & _
"FROM " & SelectedPartition & vbCr & _
"WHERE (((" & SelectedPartition & ".TUPID)=[Forms]![10_Change_BaseInformation]![TUPID]));"
DoCmd.RunSQL SQLStatement
' SQLStatement = "SELECT Resistor.TUPID, Resistor.[Hersteller] FROM ResistorWHERE (((Resistor.TUPID)=[Forms]![10_Change_BaseInformation]![TUPID]));"
End Sub
First of all, I get runtime-error "2342", but I can't make any sense of that; so: how do I have to modify my code, to get a valid result?
Second, how can I get the values from the query to the form?
Thanks in advance for your help!
I can't speak to the reason of your error, as we would need more information such as the types of your fields in your table.
I'm guessing that your Resistor.TUPID field is a string.
If so, you need to modify your code as below:
WHERE (((" & SelectedPartition & ".TUPID)='" & [Forms]![10_Change_BaseInformation]![TUPID] & "'));
If it is of Type number then
WHERE (((" & SelectedPartition & ".TUPID)=" & [Forms]![10_Change_BaseInformation]![TUPID] & "));
As to the form...
Generally speaking, you can design a form without a record source, but with controls that are named the same as your select query fields.
When designing each Control on the form, you have to explicitly specify the Control Source (i.e. The field names that are returned from your select query), otherwise they will be Unbound and never update automatically based on Record Source.
Then assign your SQL query string to the Recordsource of the form.
MyForm.Recordsource = MySQLString
Then run the Requery method of the form.
MyForm.Requery
I'm having some trouble expanding the way my data is logged. What I'm doing is connecting to an Oracle database, selecting the details and then outputting to a log file, delimited by pipes. The connection works, query works, but I'm only getting the first line of data written to my file. A search through similar situations and other recordset based questions does not return a solution. Below is the snippet of code that is actually doing any work:
sSQL = "select * from MONITOR.VP_EXPECTED_DETAILS"
rsOracle.open sSQL, sConnection
WHILE NOT rsOracle.EOF
sOracleOutput = rsOracle.Fields.Item(0)&"|" _
& rsOracle.Fields.Item(1)&"|" _
& rsOracle.Fields.Item(2)&"|" _
& rsOracle.Fields.Item(3)&"|" _
& rsOracle.Fields.Item(4)&"|" _
& rsOracle.Fields.Item(5)&"|" _
& rsOracle.Fields.Item(6)
rsOracle.MoveNext
WEND
oFile.WriteLine sOracleOutput
oFile.close
Move your WriteLine statement into your record loop.
Also:
While not directly related to your question, you can make your code much less verbose by omitting Fields and Item when retrieving row values. Item is the default property of Fields. And Fields is the default property of a Recordset object. Therefore, they can both be omitted.
sOracleOutput = rsOracle(0) & "|" & rsOracle(1) & "|" ...
First time asker, usually I can find the answer by searching, but my google-fu seems weak today.
I have an excel workbook connecting to an access 2003 database to insert usage records
The code i'm using is:
sdbpath = ThisWorkbook.Path & "\Data.mdb"
sCommand = "INSERT INTO Usage VALUES('" & Environ("Username") & "',#" & Now() & "#)"
Dim dbCon As New ADODB.Connection
Dim dbCommand As New ADODB.Command
dbCon.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & sdbpath & "; Jet OLEDB:Database Password=TestPass;"
dbCommand.ActiveConnection = dbCon
dbCommand.CommandText = sCommand
dbCommand.Execute
dbCon.Close
The code fails on the line dbCommand.Execute with run-time error '-2147217900 (80040e14)' : Automation error.
The database its trying to insert the record into contains one table, usage, with two columns - UserID and AccessDate, formatted as text and DateTime respectively.
The odd part is the connection string seems OK, since it fails after the connection is already open, yet if I take the sCommand value before the execute is run, then paste it into a query in access and execute that - it runs fine!
In case it was access struggling with the datetime format i've tried switching it to text (and the hashtags in the code) but that still fails. I've also tried specifying the column names too.
Can anyone shed some light on what i'm doing wrong? I've never had so much trouble with a very simple bit of SQL.
Thanks in advance!
In Access we need to specify the field-names. Even so, I found that I needed to wrap the table-name in square brackets before it would insert:
sCommand = "INSERT INTO [Usage] (UName, SomeDate) VALUES ('" & Environ("Username") _
& "',#" & Now() & "#)"
I am importing data from an Excel spreadsheet to a VB.NET DataTable. This Excel spreadsheet has a lot of garbage data in the first 18 rows, including a lot of empty cells. I ultimately remove these rows in post-processing, but I need to access the Excel file as is, without modifying it by hand at all.
I realize that setting IMEX=1 instructs the Jet engine to assume all columns are text. However, I have an issue with setting it to another value (explained more below). So, the default Jet engine column type scan wouldn't work particularly well.
I'd like to either:
Manually define column types before the import
Force Excel to scan many more rows (I believe the default is 8) to determine the column type
However, I do have an issue with idea #2. I do not have administrative rights to open regedit.exe, so I can't modify the registry using that method. I did circumvent this before by importing a key somehow, but I can't remember how I did it. So #1 would be an ideal solution, unless someone can help me carry out idea #2.
Is this possible? Currently, I'm using the following method:
If _
SetDBConnect( _
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & filepath & _
";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""", True) Then
dtSchema = _dh.GetOleDbSchemaTable()
If _dh.Errors <> "" Then
Throw New Exception("::LoadFileToBuffer.GetOleDbSchemaTable::" & _dh.Errors())
End If
For Each sheetRow In dtSchema.Rows
If sheetRow("TABLE_NAME").ToString() = "TOTAL_DOLLARS$" Then
totalDollars = sheetRow("TABLE_NAME").ToString()
ElseIf sheetRow("TABLE_NAME").ToString() = "TOTAL_UNITS$" Then
totalUnits = sheetRow("TABLE_NAME").ToString()
End If
Next
'Get total dollars table
sql.Append("SELECT * FROM [" & totalDollars & "]")
dtDollars = _dh.GetTable(sql.ToString())
End If
Thank you!
You should be able to say:
sql.Append("SELECT * FROM [" & totalDollars & "$A18:X95]")
Where totalDollars is a sheet name and x95 is the last valid row. You will not be able to include headers unless they are available at row 18.
I have created a sheet to extract data from a Microsoft SQL database to produce a customer report between 2 date StartDate and EndDate.
I have been playing with a few things but have not been successful in anyway. I have searched but have not been able to find anything that was what I was after or able to understand.
The problem I believe is data type of the date I am using in Excel and trying to pass it to the SQL query. I understand I need to convert this in some way to make this possible and correct.
If I manually enter dates into the query it works fine. But not practical for customer use
I am not experience with this and am just! stubbing my way through it. If someone would be so kind to me with this would be much appreciated.
Below is the code I am trying to use
Sub DataExtract()
'
DataExtract Macro
'
' Create a connection object.
Dim cni96X As ADODB.Connection
Set cni96X = New ADODB.Connection
' Set Database Range
' Provide the connection string.
Dim strConn As String
Dim Lan As Integer
Dim OS As Integer
Dim PointID As String
' Set Variables
Lan = Range("Lan").Value
OS = Range("OS").Value
PointID = Range("PointID").Value
StartDate = Range("StartDate").Value
EndDate = Range("EndDate").Value
'Use the SQL Server OLE DB Provider.
strConn = "PROVIDER=SQLOLEDB;"
'Connect to 963 database on the local server.
strConn = strConn & "DATA SOURCE=(local);INITIAL CATALOG=i96X;"
'Use an integrated login.
strConn = strConn & " INTEGRATED SECURITY=sspi;"
'Now open the connection.
cni96X.Open strConn
' Create a recordset object.
Dim rsi96X As ADODB.Recordset
Dim rsi96X1 As ADODB.Recordset
Set rsi96X = New ADODB.Recordset
Set rsi96X1 = New ADODB.Recordset
With rsi96X
' Assign the Connection object.
.ActiveConnection = cni96X
' Extract the required records1.
.Open "SELECT ModuleLabel, originalAlarmTime FROM LastAlarmDetailsByTime WHERE (os = " & OS & " And theModule = N'" & PointID & "'AND AlarmCode = N'DI=1' And lan = " & Lan & " And originalAlarmTime BETWEEN N'" & StartDate & "' AND N'" & EndDate & "') ORDER BY originalAlarmTime DESC"
' Copy the records into sheet.
Range("PointLabel, TimeCallInitiated").CopyFromRecordset rsi96X
With rsi96X1
.ActiveConnection = cni96X
' Assign the Connection object.
.Open "SELECT originalAlarmTime FROM LastAlarmDetailsByTime WHERE (os = " & OS & " And theModule = N'" & PointID & "'AND AlarmCode = N'CDI1' And lan = " & Lan & " And originalAlarmTime BETWEEN N'" & StartDate & "' AND N'" & EndDate & "')ORDER BY originalAlarmTime DESC"
' Copy the records into sheet.
Sheet1.Range("TimeCallEnded").CopyFromRecordset rsi96X1
' Tidy up
.Close
I hope this makes sense.
You cannot specify the data types, the Access database engine (formerly Jet) must guess. You can influence its guesswork by changing certain registry settings (e.g. MaxScanRows) and including IMEX=1 in the connection string. For more details, see this knowledge base article.
Here's something I wrote on the subject many years ago (if you google for "ONEDAYWHEN=0" you can see it has been widely read though perhaps not carefully enough!):
The relevant registry keys (for Jet 4.0) are in:
Hkey_Local_Machine/Software/Microsoft/Jet/4.0/Engines/Excel/
The ImportMixedTypes registry key is always read (whether it is
honored is discussed later). You can test this by changing the key to
ImportMixedTypes=OneDayWhen and trying to use the ISAM: you get the
error, "Invalid setting in Excel key of the Engines section of the
Windows Registry." The only valid values are:
ImportMixedTypes=Text
ImportMixedTypes=Majority Type
Data type is determined column by column. 'Majority Type' means a
certain number of rows (more on this later) in each column are scanned
and the data types are counted. Both a cell's value and format are
used to determine data type. The majority data type (i.e. the one with
the most rows) decides the overall data type for the entire column.
There's a bias in favor os numeric in the event of a tie. Rows from
any minority data types found that can't be cast as the majority data
type will be returned with a null value.
For ImportMixedTypes=Text, the data type for the whole column will be:
Jet (MS Access UI): 'Text' data type
DDL: VARCHAR(255)
ADO: adWChar ('a null-terminated Unicode character string')
Note that this is distinct from:
Jet (MS Access UI): 'Memo' data type
DDL: MEMO
ADO: adLongVarWChar ('a long null-terminated Unicode string value')
ImportMixedTypes=Text will curtail text at 255 characters as Memo is
cast as Text. For a column to be recognized as Memo, majority type
must be detected, meaning the majority of rows detected must contain
256 or more characters.
But how many rows are scanned for each column before is decided that
mixed and/or what the majority type is? There is a second registry
key, TypeGuessRows. This can be a value from 0-16 (decimal). A value
from 1 to 16 inclusive is the number of rows to scan. A value of zero
means all rows will be scanned.
There is one final twist. A setting of IMEX=1 in the connection
string's extended property determines whether the ImportMixedTypes
value is honored. IMEX refers to 'IMport EXport mode'. There are three
possible values. IMEX=0 and IMEX=2 result in ImportMixedTypes being
ignored and the default value of 'Majority Types' is used. IMEX=1 is
the only way to ensure ImportMixedTypes=Text is honored. The resulting
connection string might look like this:
Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=C:\ db.xls;
Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'
Finally, although it is mentioned in MSDN articles that MAXSCANROWS
can be used in the extended properties of the connection string to
override the TypeGuessRows registry keys, this seems to be a fallacy.
Using MAXSCANROWS=0 in this way never does anything under any
circumstances. Put another way, is has just the same effect as putting
ONEDAYWHEN=0 in the extended properties, being none (not even an
error!) The same applied to ImportMixedTypes i.e. can't be used in
the connection string to override the registry setting.
In summary, use TypeGuessRows to get Jet to detect whether a 'mixed
types' situation exists or use it to 'trick' Jet into detecting a
certain data type as being the majority type. In the event of a
'mixed types' situation being detected, use ImportMixedTypes to tell
Jet to either use the majority type or coerce all values as Text
(max 255 characters).
Try changing the date part of your SQL statement to:
"[...] originalAlarmTime BETWEEN '" & Format$(StartDate, "yyyy-mm-dd") & "' AND '" & Format$(EndDate, "yyyy-mm-dd") & "' [...]"
You might also try using a parameterized query.