External database path as parameter for parametrized query to Access - sql

I'm writing small VB.Net app which should build reports based on data gathered from some external MDB-files (Access 2007). It was planned that this app will use parametrized SQL queries to collect data. One of the parameters for these queries is path to the external MDB-file.
Here goes sample code:
Dim conn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" _
& "Data Source=C:\Temp\Temp.mdb;")
conn.Open()
Dim cmd As New OleDbCommand()
cmd.Connection = conn
cmd.CommandType = CommandType.Text
cmd.CommandText = "SELECT * INTO Trend FROM TI IN '?' WHERE TI.Id=?;"
With cmd.Parameters
.Add("#p1", OleDbType.VarChar).Value = "C:\Temp\Source.mdb"
.Add("#p2", OleDbType.Integer).Value = 5
End With
cmd.ExecuteNonQuery()
conn.Close()
Looks simple but it doesn't works. After launch my app throws following exception - System.Data.OleDb.OleDbException: Disk or network error.
Have spent a whole day to make it work with no success. What have I done wrong?

This is a comment that others have suggested is the answer to the question:
Nothing in an Access/Jet/ACE FROM clause is parameterizable (unless it's inside a subquery, of course).
With Access/Jet/ACE your only choice is to use some other method to write the FROM clause on-the-fly.

Related

Why wont my SET value WHERE SQL Statement not work

Currently cant get this to work, despite it being almost for verbatim the same as else where in my code.
Using con As New OleDbConnection(constring)
Using cmd As New OleDbCommand("UPDATE " & "`" & "SIQPERSIST" & "`" & " SET [Date_Added] = #Date_Added WHERE [BatchName] = #BatchName", con)
cmd.Parameters.AddWithValue("#BatchName", BatchName2)
cmd.Parameters.AddWithValue("#Date_Added", Date.Now.ToShortDateString)
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End Using
End Using
I'm working in Vb.net
and i need to update all rows that have the name BatchName2 (this comes from a textbox)
with the current date.
The table they are on is SIQPERSIST.
The error i get is that its missing a parameter.
But i have don't know what parameter it needs despite almost similar code working else where, except the working code uses a WHERE KEY= 'keynumber' statement.
The issue is this uses backticks for the concatenated variable. Remember, ` and ' are not the same thing, and only one of those would work here.
It should look like something more like this:
Using con As New OleDbConnection(constring)
Using cmd As New OleDbCommand("UPDATE SIQPERSIST SET [Date_Added] = Date() WHERE [BatchName] = #BatchName", con)
cmd.Parameters.AddWithValue("#BatchName", BatchName2)
con.Open()
cmd.ExecuteNonQuery()
End Using
End Using
Note, there's no need to call con.Close() when you have a Using block to take care of that for you.
Additionally, not only did I convert BatchName2 to a real query parameter (Shame on you for adding concatenation to a query that already demonstrates how to use parameters!), but I was also able to convert the existing parameter to use get the date in the DB itself.

vb.net procedure or function expects parameter which was not supplied

This seems so simple, but I can't resolve the error
Procedure or function 'test' expects parameter '#id', which was not supplied.
I have tried a dataadapter instead of the reader, tried the {call test (?)} syntax, and several variants on how to add the parameter.
CREATE PROCEDURE [dbo].test (#id int)
AS
BEGIN
select * from tmptable where id=#id
END
Using conn = New OdbcConnection(connstring)
conn.Open()
Dim cmd As OdbcCommand = New OdbcCommand("test", conn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#id", 6)
Dim reader As OdbcDataReader = cmd.ExecuteReader()
reader.Close()
conn.Close()
End Using
Try dropping the # - so AddWithValue("id",6) instead. I usually explicitly create the parameter and add it to the collection, and when I do I drop the # sign from the parameter name.
Also, I'll modify your code to look like how I usually use it and edit it into my post in a few minutes, if dropping the # doesn't work you can try my style, maybe there are some subtle differences.
EDIT: Oops, my bad, I use the explicitly defined parameters with SQLcommands, not ODBC commands! You can try leaving out the #, but I don't have a working example I can share with you, sorry :-(
EDIT 2: OK, I don't have an example, but Microsoft has one that looks a lot more like how I call my stored procedures using SQLCommands, see
http://msdn.microsoft.com/en-us/library/system.data.odbc.odbcparametercollection%28v=vs.90%29.aspx
Basically, I think your code would look like
Using conn = New OdbcConnection(connstring)
conn.Open()
Dim cmd As OdbcCommand = New OdbcCommand("{ call test(?) }", conn)
cmd.CommandType = CommandType.StoredProcedure
' replace this with the following cmd.Parameters.AddWithValue("#id", 6) '
Dim ParamID As New OdbcParameter()
ParamID.DbType = DbType.Int32
ParamID.Value = 6
cmd.Parameters.Add(ParamID)
' end replace '
Dim reader As OdbcDataReader = cmd.ExecuteReader()
reader.Close()
conn.Close()
End Using
And you should also be aware that some ODBC drivers are not good at getting recordsets back from stored procedures. I use SmallTalk to query DB2 through ODBC, and I can get a recordset back from a function, but not from a stored procedure. You may be encountering a similar limitation. What database are you using?

please help retrieving data to put it on label

I want to retrieve the price from table Products to use it as label2 on the orderinfo form.
Dim con As New OleDb.OleDbConnection
Dim com As New OleDb.OleDbCommand
com = New OleDb.OleDbCommand("Select Price FROM Products WHERE ProductName='" & ListBox1.SelectedItem.ToString & "'", con)
con.ConnectionString = "PROVIDER = Microsoft.ACE.OLEDB.12.0; Data Source=Database_AntoninosCafe.accdb"
con.Open()
com.ExecuteNonQuery()
orderInfo.Label2.Text = retrieve data
con.Close()
The correct approach to your simple problem
Dim cmdText = "Select Price FROM Products WHERE ProductName=?"
Using con = New OleDb.OleDbConnection( ... connection string here ...)
Using com = New OleDb.OleDbCommand(cmdText, con)
com.Parameters.AddWithValue("#p1", ListBox1.SelectedItem.ToString)
con.Open()
Using reader = com.ExecuteReader()
if reader.Read() Then
orderInfo.Label2.Text = reader("Price").ToString
End If
End Using
End Using
End Using
The first thing is to use a parameterized query to avoid sql injections and parsin problems, then use the Using statement to encapsulate you disposable object in a block of code that ensures the closing and disposing of these objects.
Finally, to read data from a datatable you use the ExecuteReader command that returns an OleDbDataReader instance. It is this instance that could be used to extract the data from your database
As a side note, I have used, as placeholder for the parameter, a question mark. This is the predefined symbol used by OleDb. But, when adding the parameter value to the collection, I have used a different name (#p1). This is acceptable because OleDb do not use the parameter names to find the corresponding placeholders in the query text like the SqlClient or other providers, but use the position of the placeholder. So, first placeholder replaced by the first parameter and so on.

Cant save or update my SQL Server tables using vb.net

I am a complete beginner to .net and am confused at some basic things. Please help.
First of all the table I create and populate (by right clicking tables in server explorer) disappear once I restart the computer. how do I keep them.
Is there any better place/interface to type SQL queries in vb.net than the command prompt.
In the following code:
Dim cn As SqlConnection = New SqlConnection(strConnection)
cn.Open( )
' Create a data adapter object and set its SELECT command.
Dim strSelect As String = _
"SELECT * FROM Categories"
Dim da As SqlDataAdapter = New SqlDataAdapter(strSelect, cn)
' Load a data set.
Dim ds As DataSet = New DataSet( )
da.Fill(ds, "Categories")
This far the code runs fine but just to gain better understanding, I would like to ask that
while data from SQL Server database was saved into da in accordance to the query, why do we need to save/transfer it in the dataset object ds.
Is there any additional benefit of SqlCommand over SqlDataAdapter besides speed?
Dim autogen As New SqlCommandBuilder(da)
Dim dt As DataTable = ds.Tables("Categories")
' Modify one of the records.
Dim row As DataRow = dt.Select("CategoryName = 'Dairy Products'")(0)
row("Description") = "Milk and stuff"
gives an error when I use it with
da.Update(ds, "Categories")
regarding dt.select not returning any value.
What is the way out?
to answer your questions :
The tables you create with the server explorer are IN MEMORY. Same goes for dataset, they are in-memory representation of your table. As for your 2nd example, the DS you use isnt filled when you try to get the DT. hence why the DT is empty.
If your starting, I would suggest you go look into Linq-to-Sql (http://msdn.microsoft.com/en-us/library/bb425822.aspx) for a more up-to-date way of doing sql in .net ( I think its 4.0 framework)
As for the 2nd point, I'd say normally you should use store procedure for most of your sql commands .. the sqlcommand is use like this
Try
Cmd = New SqlClient.SqlCommand("st_InventoryStatus_Or_AnyStoreProcName_Or_ASqlQuery")
Cmd.CommandTimeout = 300 'not really needed'
Cmd.CommandType = CommandType.StoredProcedure 'you can type CommandType.Text here to use directly your "Select * from Category"'
Cmd.Parameters.Clear() 'just to be sure its empty, its not mandatory'
Cmd.Parameters.Add("#idCategory", SqlDbType.Int).Value = myCategory.Id 'here are the parameters of your store proc, or of your query ("select * from Category where Category.id = #Id")'
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Information)
End Try

Cannot connect to dbf file

I'm trying to connect to to a foxpro table (.dbf) from a test vb.net form.
I recieve an OleDbException with the message "Cannot open file c:\emp\emptbl.dbf"
Have tried with both of the following connection strings:
Provider=VFPOLEDB.1;Data Source=C:\emp\emptbl.dbf
from the MSDN article here
Provider=vfpoledb;Data Source=C:\emp\emptbl.dbf;Collating Sequence=machine;
from connectionstrings.com
The latter seems to be the type to use when connecting to a single table, but the same exception is thrown regadless of which is used.
I can open and perform the same query okay in visual foxpro 6.0.
Here's my code:
Dim tbl As DataTable = New DataTable()
Using con = New OleDbConnection(conString)
cmd = New OleDbCommand() With {.Connection = con, .CommandType = CommandType.Text}
Dim sSQL As String = "SELECT * FROM(EMPTBL)"
cmd.CommandText = sSQL
Dim adp As OleDbDataAdapter = New OleDbDataAdapter(cmd)
Dim ds As DataSet = New DataSet()
con.Open()
adp.Fill(ds)
con.Close()
If (ds.Tables.Count > 0) Then
tbl = ds.Tables(0)
End If
End Using
Return tbl
The OleDB provider should only connect to the PATH where the tables are... not the actual file name. Once you connect to the PATH, you can query from ANY .Dbf file that is located in it
Provider=VFPOLEDB.1;Data Source=C:\emp
select * from emptbl where ...
You can also look at other connection string settings at
ConnectionStrings.com
UPDATE per comment.
It appears you are getting closer. with your attempt without the () parens. In VFP, within parens, it interprets that as "look for a variable called EMPTBL", and from its value is the name of the table to query from. Not something you would need to apply via OleDB connection.
Now, cant open the file is another. Is it POSSIBLE that another application has the table open and the file is in exclusive use? and thus can not be opened by the .net app too? Even for grins, if you open VFP, and just do a simple create table in the C:\Emp folder and put a single record in it, then you know no other program will be using it as it is a new file. Quit out of VFP and try to query THAT table. There should be no locks, no other program is expecting it, so it should never be opened by anything else and you should be good to go.