VB.NET - Visual Foxpro OLE DB Problem with Numeric Decimal Column - vb.net

In Short:
I'm using VB.NET 2008 to connect to a Visual Foxpro 6 Database using the vfpoledb.1 driver. When I attempt to fill an OleDbDataAdapter with a dataset table that contains one of the numeric columns, I get the following error message:
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.
I'd like to retrieve this column from VB.NET 2008 and keep it in a numeric format.
The Long Version:
I'm using VB.NET to connect to a Visual Foxpro 6 database. Several of the columns in the table are intended for numeric data type of up to 8 digits. I'm not sure how Visual Foxpro data types work but it appears that this field allows someone to enter any of the following example values:
99999999
99999.99
9.99
9.00
{nothing}
From Visual Foxpro: I have access to small program called Foxwin that allows me to browse the VFP tables in a native VFP environment. This is what I'm using to access the data to obtain my examples for what I posted above. From here I can see that some rows contain no values at all in this field although they appear to be filled with spaces when there is no data. I've tried to run update queries to fill in every row with valid data but my update queries finish without updating any rows. I've tried ISNULL(bal_qty) and bal_qty IS NULL and neither one works.
From MS Access 2007: Using the same driver that I'm using in VB.NET and I can load the ADO recordset and bind it to a form without a problem. The decimal values appear to be stripped off, probably because all of them are ".00". I prefer to build this small program in VB.NET so I'm using MS Access only for testing.
From VB.NET: My SQL statement works if I convert bal_qty to String but this causes sort problems. I've tried VAL(STR(bal_qty)) and it fails with the same error message I've posted above. Here's the code I'm using:
Imports System.Data.OleDb
Public Class Form1
Dim sConString As String = "Provider=vfpoledb.1;Data Source=C:\MyDatabase.dbc;Mode=3;"
Dim con As OleDbConnection = New OleDbConnection(sConString)
Private Function FetchData()
con.Open()
Dim ds As DataSet = New DataSet()
Dim sSQL As String
'This SQL statement works but the data doesn't sort properly.
'sSQL = "SELECT item_cd, item_desc, STR(bal_qty) FROM invent;"
sSQL = "SELECT item_cd, item_desc, bal_qty FROM invent;"
Dim cmd As OleDbCommand = New OleDbCommand(sSQL, con)
Dim daInv As OleDbDataAdapter = New OleDbDataAdapter(cmd)
Dim iRecCount As Integer
iRecCount = daInv.Fill(ds, "invent") 'The error occurs here.
Me.DataGridView1.DataSource = ds.Tables("invent").DefaultView
End Function
Private Sub btnFetchData_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnFetchData.Click
Call FetchData()
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
con.Close()
con = Nothing
End Sub
End Class

We have this problem with a .NET app that reads foxpro dbf's. Our solution was to use the following in the select statement:
SELECT PropertyID, VAL(STR(SaleAmt)) as SaleAmt FROM MyTable
This converts the decimal column (SaleAmt) to a string and then back to a numeric value. Additionally, if an integer is desired, you can use INT(SaleAmt) in your SELECT statement.

I've found the problem that was causing this. In the bal_qty column/field there was numeric data entered that didn't conform to the column's data type definition.
My field bal_qty has a Visual Foxpro data definition of:
Type: Numeric
Width: 8
Decimal: 2
The Visual Foxpro software apparently allowed the user to enter a value of 1000987 in this field which, as near as I can tell, doesn't 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.
Further testing revealed that MS Access 2007 also has a problem with this value. After loading the recordset into my Datasheet view form I get the error: "Data provider or other service returned an E_FAIL status." If I include the following WHERE clause I do not get the error: WHERE bal_qty < 9999
I've now resolved the problem by running an SQL UPDATE statement to change the value of bal_qty in the offending record.
I also found bad data in a column called markup. Hundreds of records are showing only asterisks where they should be showing numeric data. Including this markup column in my recordset queries causes my queries to fail with errors also.
See this SO Post concerning Asterisks in Numeric Columns and how to deal with it from .NET:
How do I read asterisk (***) fields from .DBF data base?
If you're trying to resolve this problem you can view and edit VFP data natively using Visual RunFox 6 which is free on Ed Leafe's website: http://leafe.com/dls/vfp You can also edit the table structure from here. This tool is far from intuitive unless you are an experienced VFP programmer. You have to enter VFP commands from the command window for most everything you want to do.

I've worked with VFP through C# and VB with many tables with/without decimals without problems. As for the ordering of data, you could add the "order by" clause to the select so its default coming DOWN from VFP into VB in a presorted mode.
Additionally, in the version's I've built, I don't query into a dataset, and don't know if that might be a problem somewhere somehow...
dim dt as DataTable
dim sSQL as String
sSQL = "Select item_cd, item_desc, bal_qty from invent order by bal_qty"
then, your data adapter...
daInv.Fill( dt )
then you would still be able to bind directly to your grid...
Me.DataGridView1.DataSource = dt
As for the numeric content, from your DBF Viewer utility, the input mask of the table structure should default to its expecting values... browse to any record, get into th field and start typing "9.99999", so "9." will force you to ITs known decimal location, then keep typing 9's after the decimal see how many actual places ARE available. I could see how it might nag you if you try to put in a value with greater decimal precision than it allows.

Related

How to edit a record in an access database - visual basic

I want to edit a specific record in an access database but I keep on getting errors
this is the database I want to edit:
Access database
these are flashcards that the user has created and stored in an access database. What I want is that the user is able to edit the difficulty so it appears more/less often
This is the module:
Module Module1
Public Function runSQL(ByVal query As String) As DataTable
Dim connection As New OleDb.OleDbConnection("provider=microsoft.ACE.OLEDB.12.0;Data Source=flashcard login.accdb") 'Establishes connection to database
Dim dt As New DataTable 'Stores database in table called dt
Dim dataadapter As OleDb.OleDbDataAdapter
connection.Open() 'Opens connection
dataadapter = New OleDb.OleDbDataAdapter(query, connection)
dt.Clear() 'Clears datatable
dataadapter.Fill(dt) 'Fills datatable
connection.Close()
Return dt
End Function
End Module
And here is the button that the user can press to edit the database:
Private Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click
Dim sql As String
sql = "UPDATE flashcards set difficulty = '" & TxtDifficulty.Text
runSQL(sql)
End Sub
The difficulty column in the database should be able to be edited by the user through the value they entered in txtDifficulty.text
Good to hear I found the problem with the apostrophe.
I am going to need a where statement but the problem I have is that the user can create as much flashcards as they want so how would I write the where statement?
An INSERT statement does not have a WHERE clause but an UPDATE does and is usually by a primary key.
Look at how I add a new record ignoring mHasException and specifically using parameters. In this case a List is used but with little effort an array of DataRow can be passed instead.
Here is an example for updating a record with a DataRow.
To get other code samples for ms-access see the following repository.
In closing, in the above repository I don't get into all possibilities yet there should be enough there to get you going. And when reviewing code I flip between Add for adding a parameter and AddWithValue while Add is the recommend way but both are shown to see differences. see also Add vs AddWithValue.

VB.NET Clear DataTable then Fill AFTER Successfully Getting New Data

I currently use a TableAdapter to fill() a typed datatable in a typed dataset. ClearBeforeFill is set to True as the underlying data is different each time. The problem is that in the case the database is unreachable, the old data gets cleared before it knows. I want the old data to stay in the datatable (and subsequently stay displayed) in the case an error occurs retrieving from the database. Ideally, I'd still use a tableAdapter and the GetData() method instead of the Fill() method but I can't seem to figure out how to replace the current datatable with the one returned by GetData(). Tables.Remove() then Tables.Add() doesn't seem to work. Below code gives an error: "'table' argument cannot be null." & vbCrLf & "Parameter name: table"
Dim TempTbl As DS_ERecord.DT_spRefreshAndSelectStepConnectorMonitorDataTable
TempTbl = TAi_spRefreshAndSelectStepConnectorMonitor.GetData(ForceRefresh, CmbMonitorView.SelectedValue)
DSi_ERecord.Tables.Remove(DSi_ERecord.DT_spRefreshAndSelectStepConnectorMonitor)
DSi_ERecord.Tables.Add(TempTbl)

show invalid DateTimes

I made an application that shows me the full content of a table in an OracleDatabase where i only have restricted access to.
The Application simply takes the User-Entered Server IP, login-details and command from textfields and sends the command to the Oracle server. The Application is used to just show the Content of Tables i have access to.
I have the same Database 2 times with different values. While its working for the first database, the second one is giving me the following Error-Message
year month and day parameters describe an un-representable datetime
(I am getting the german version of the Error-Msg, but this should be it)
This Error is Caused due to invalid dates in the Values (example 99.99.2014, dates that do not exist)
I am not allowed to change values in the Oracle Database, but i need to view the values to print the birthdate on a paper later in another application.
My theory solution is the following: Make the Date that i get from the server be shown as a string, not as date - My Problem: I dont know how
My Program (VB) is doing the following:
Get User entrys -> send select command to server -> put results into datatable -> use datatable as datasource for Datagridview
EDIT
Public Sub New(ByRef OracleConnection As Oracle.ManagedDataAccess.Client.OracleConnection, Command As String)
InitializeComponent()
Try
Dim oraCommand As New Oracle.ManagedDataAccess.Client.OracleCommand(Command, OracleConnection)
Dim OraDA As New Oracle.ManagedDataAccess.Client.OracleDataAdapter(oraCommand)
Dim dt As New DataTable
OraDA.Fill(dt)
dgv.DataSource = dt
Cursor = Cursors.Default
dgv.Columns(dgv.ColumnCount - 1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
Catch ex As Exception
MessageBox.Show(ex.Message)
OracleConnection.Close()
End Try
End Sub
by removing the try/catch i found out the error comes in the following line
oraDA.Fill(dt)
the command is typically something like select * from database.table where the Date column is called GEBDATUM

Query Access Visual Basic

I am trying to figure out how to query an access db using visual basic but I'm looking for a little explanation on how this actually works.
What I'm confused about is that I state a command SELECT * FROM PI (PI Being the table) but then directly below that, I'm saying that TextBox1.Text = theDataTable.Rows(0).Item(1).
I'm just wondering why I have a query command and then a seperate command that is going to a specified Row and Item....any help is much appreciated!
Imports System.Data.OleDb
Public Class Form1
Dim theConnectionString As New OleDbConnection
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
txtSQL.Clear()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
theConnectionString.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Marc Wilson\Documents\FiddleFuckDB.accdb"
theConnectionString.Open()
Dim theDataSet As New DataSet
Dim theDataTable As New DataTable
theDataSet.Tables.Add(theDataTable)
Dim theDataAdapter As New OleDbDataAdapter
theDataAdapter = New OleDbDataAdapter("SELECT * FROM PI", theConnectionString)
theDataAdapter.Fill(theDataTable)
TextBox1.Text = theDataTable.Rows(0).Item(1)
theConnectionString.Close()
End Sub
End Class
Like this
"SELECT * FROM PI Where FieldName = '" & TextBox1.Text & "'"
assumed that your field type is not numeric
Since you're using an ADO.NET DataTable - that object consist of Rows collection and each row in turn consists of Items collection. So in order to get to a specific value you need to use
Table.Rows(X)(Y)
notation. Even if your query returns a single value - you would use this approach. Looking at your code and Items(1) especially, it looks like your query returns at least 2 columns.
If you're interested in a single value only, consider specifying a single column name in your query, make sure that it returns a single row (e.g. by adding WHERE clause to your query) and use ExecuteScalar ADO.NET command, which, unlike Fill and DataTable returns a single value only.
Not 100% sure I undertand the question, but hopefully this helps:
The query command is fetching all of the records from the table in your database. The Rows() and Item() methods fetch a particular field from a particular record (in this case, the second field of the first record).
The Text property of your TextBox cannot display the entire table on it's own: the DataTable is a fairly complicated data strucutre. TextBoxes require a string (or something like one).
SELECT * FROM PI tells the database engine which data it should retrieve from the underlying database table that exists on-disk.
You're using the DataTable class which represents data in-memory: the DataAdapter class reads data from disk (using the SQL statement) and copies it into memory, where you then use the Rows(0).Item(1) command to get a copy of the data already in memory.
The alternative is to use DataReader which is more direct, often simpler. In your case I don't see why you're using the DataTable class because DataReader will suit you fine.

Replicating table rows in a datatable causes the datatype in an Excel output report to be different?

I pull a report from SQL Server being not a fan of cursors I process that table server side in my code behind file. So I pull this report that is an address label report and my client wants there to be X number of labels per person. So I coded this function:
Private Function ProcessX(ByVal dt As DataTable, ByVal X As Integer) As DataTable
Dim dtProcessed As DataTable = dt.Copy
dtProcessed.Clear()
For Each dr As DataRow In dt.Rows
For i As Integer = 0 To X - 1
Dim drHolder As DataRow = dtProcessed.NewRow
drHolder.ItemArray = dr.ItemArray
dtProcessed.Rows.Add(drHolder)
Next
Next
Return dtProcessed
End Function
Which the function works beautifully and it processes much faster than a cursor in a sproc. The problem with this particular report is that when I export it to excel it chops off the leading 0s of zip codes that start with 0. I also have zip+4 and international zip codes that are returned in the same pull. Normally I would just chalk this up to a standard excel glitch on how it handles leading 0s, but when I don't process the report through the above function Excel does not chop off my leading 0s.
I stepped through the function and the datatype for the column in question is the same before and after the process and matches the datatype of the original table. The only thing I can think of is maybe because I am passing the datatable object ByVal instead of ByRef? I don't know I have tried almost everything else including copying each row item by value and recreating the datatable by hand. Nothing seems to change the outcome.
I found a solution and I am not happy with it, but it works.
SELECT [ZipCode] = ' ' + ISNULL(TABLE.ZipCode,'')
FROM TABLE
...
Both the online report and excel interpret it as an empty space and it doesn't mess with my formatting.