C# VFP OLEDB query throwing "Command contains unrecognized phrase/keyword" - c#

I have a C# application intended to update one field in a table based on a value found in another table. Using the following:
listComm.CommandText = "update [c-disc] inner join [c-info] " +
"on [c-info].keys = [c-disc].cd_key set [c-disc].cd_distric = ? " +
"where [c-disc].cd_tax = ? and [c-info].ci_region = ?";
and in a foreach loop below it:
string region = line.Substring(0, 4).PadRight(14);
string taxable = "Y";
string district = line.Substring(5, 4).PadLeft(4);
listComm.Parameters.Add(new OleDbParameter("?", district));
listComm.Parameters.Add(new OleDbParameter("?", taxable));
listComm.Parameters.Add(new OleDbParameter("?", region));
try {
listComm.ExecuteNonQuery();
listComm.Parameters.Clear();
} catch (Exception x) {
setStatusText("fatal error: " + x.Message.ToString();
}
I'm getting "Command contains unrecognized phrase/keyword". Using the same query in MS Access works fine when I plug the appropriate values in place of the '?' placeholders. In Visual Studio, using breakpoints I see everything appears normal - the connection is open and the parameter values are as expected. I have another program that works similarly, but only against a single table. I can't for the life of me figure out what's wrong with this query.

Whoever designed that system, sounds to not have much knowledge about VFP. VFP is not totally ANSI SQL compatible and not only that have some naming rules. Your designer named the tables with dash in them? In documentation there are warnings as I remember. Anyway you can still go with that hoping, cd_key and cd_tax fields are only in 'c-disc' table (otherwise you need a little bit workaround).
using (OleDbConnection con = new OleDbConnection(#"Provider=VFPOLEDB;Data Source=c:\MyDataFolder"))
{
var sql = #"update [c-disc]
set cd_distric = ?
from [c-info] ci
WHERE ci.keys = cd_key AND
cd_tax = ? and ci.ci_region = ?";
var listComm = new OleDbCommand(sql, con);
listComm.Parameters.Add("dst", OleDbType.Char);
listComm.Parameters.Add("tx", OleDbType.Char);
listComm.Parameters.Add("reg", OleDbType.Char);
string taxable = "Y";
listComm.Parameters["tx"].Value = taxable; // constant?
con.Open();
// Loop here
// {
// These paddings do not smell good
string region = line.Substring(0, 4).PadRight(14);
string district = line.Substring(5, 4).PadLeft(4);
listComm.Parameters["dst"].Value = district;
listComm.Parameters["reg"].Value = region;
try
{
listComm.ExecuteNonQuery();
}
catch (Exception x)
{
setStatusText("fatal error: " + x.Message.ToString());
}
// loop ends here
// }
con.Close();
}

Related

Trying to pull Testimonials from a database in C#; Receiving error 8178 and Parameterized Query Expects the Parameter ____ which was not supplied

I'm very new to backend development, and I'm feeling a bit stuck with accomplishing my goal here. I'm trying to pull testimonials and blurbs out of an SQL database and have them populate on the page that I've built. Currently, the code that I've written does nothing but pull an error (8178) and tell me that it expects a parameter that hasn't been supplied. Any guidance would be appreciated. I feel like it's something rather small that I'm missing, but I haven't had any luck in figuring it out.
This currently will provide the Response.Write that I've included, and that's working, but I can't seem to figure out what is stopping me from pulling the info off of the database. I've checked that my connection String is correct and active.
//This will load blurbs that will initially appear on page.
protected void Page_Load(object sender, EventArgs e)
{
//BlurbID = Session["Blurb"];
Page.Title = "Testimonials";
try
{
sqlConnectionStr.Open();
SqlCommand getBlurb = new SqlCommand(#"SELECT b.BlurbID,
b.BlurbText
FROM TestimonialBlurb b LEFT JOIN Testimonial t ON
t.BlurbID = b.BlurbID WHERE t.BlurbID=#BlurbID", sqlConnectionStr);
getBlurb.Parameters.AddWithValue("#BlurbID", SqlDbType.Int);
getBlurb.Parameters.AddWithValue("#BlurbText", SqlDbType.VarChar);
DataTable userBlurb = new DataTable();
using (SqlDataAdapter blurbDA = new SqlDataAdapter(getBlurb))
{
blurbDA.Fill(userBlurb);
DataView blurbDV = new DataView(userBlurb);
if (blurbDV.Count < 1)
{
Response.Write("There are currently no testimonials available.");
}
else
{
for (int i = 0; i < blurbDV.Count; i++)
{
blurbPH.Controls.Add(new Literal
{
Text = blurbDV[i].Row["BlurbText"].ToString() + "<strong> " + blurbDV[i].Row["Blurb"].ToString() + "</strong>"
});
}
}
}
}
catch (Exception ex)
{
blurbPH.Controls.Add(new Literal
{
Text = ex.ToString()
});
}
finally
{
sqlConnectionStr.Close();
}
You have this query:
sqlConnectionStr.Open();
SqlCommand getBlurb = new SqlCommand(#"SELECT b.BlurbID,
b.BlurbText
FROM TestimonialBlurb b LEFT JOIN Testimonial t ON
t.BlurbID = b.BlurbID WHERE t.BlurbID=#BlurbID", sqlConnectionStr);
You can see here that you have no need for #BlurbText as only #BlurbID is used in the query. We can remove that parameter.
Now, let's look at your parameter that you're adding:
getBlurb.Parameters.AddWithValue("#BlurbID", SqlDbType.Int);
When you use AddWithValue, the second argument is the value you're assigning to #BlurbId. Clearly this is not what we want. I think you've got this mixed up with Add.
We can thus write it correctly as:
getBlurb.Parameters.Add("#BlurbID", SqlDbType.Int).Value = 5;
The value 5 would then be used where #BlurbID appears in your query.
By the way, you don't need to read into a DataTable to access your data, only to create a new object. You can just use SqlDataReader:
getBlurb.Parameters.Add("#BlurbID", SqlDbType.Int).Value = 5;
using (SqlDataReader reader = getBlurb.ExecuteReader())
{
while (reader.Read())
{
blurbPH.Controls.Add(new Literal
{
Text = reader["BlurbText"].ToString() + "<strong> " + reader["Blurb"].ToString() + "</strong>"
});
}
if (blurbPH.Controls.Count == 0)
{
Response.Write("There are currently no testimonials available.");
}
}
Side note for using .Add with string values. You should use this overload. If your column type in the database is a varchar(255) then adding a string should look like this:
myCommand.Parameters.Add("#MyParameter", SqlDbType.VarChar, 255).Value = "Hello";
Note how we specify the length of the field here.
Following lines, the code needs to be updated
getBlurb.Parameters.AddWithValue("#BlurbID", SqlDbType.Int);
getBlurb.Parameters.AddWithValue("#BlurbText", SqlDbType.VarChar);
as
getBlurb.Parameters.AddWithValue("#BlurbID", 1001);//Considering 1001 as as the ID BlurbID
and #BlurbText Parameter does not exist in the SQL query any need to pass it.
If you are using AddWithValue then no need to set the SqlDbType.

Data Type Mismatch when evaluating Access Calculated Fields in Visual c# using Microsoft Access Database Engine

I have a OleDbCommand in a Visual Studios c# windows forms project, and I am trying to select the name of every item in my Access Table Stock where the value of a calculated field in that table is less than one. The result type of the calculated field in Access is set to decimal, and the code looks as if it should work, but for whatever reason it doesn't. Could you help me?
Here is my code:
loginForm.connection.Open();
stockLowString = "";
var checkStockLowCommand = new OleDbCommand("SELECT stockName FROM Stock WHERE (stockLowCalculation < '" + Convert.ToDecimal(1) + "')",loginForm.connection);
OleDbDataReader checkStockLowReader = checkStockLowCommand.ExecuteReader();
while (checkStockLowReader.Read())
{
stockLowString = stockLowString + checkStockLowReader.GetString(0) + " ";
}
if (stockLowString != "")
{
MessageBox.Show("There are some Stock Items that are low, these are" + Environment.NewLine + stockLowString);
}
loginForm.connection.Close();
The error occurs on the line
OleDbDataReader checkStockLowReader = checkStockLowCommand.ExecuteReader();
Thanks in advance for your help.
Problem Solved, or at least avoided. I just put the calculation in the Command rather than use a calculated field.
The question is still valid though, as I didn't solve it.
Open the database and check the type of the field "stockLowCalculation" it's most likely not decimal.. I suggest you rework your query and make it parametrized. This way you would evade most of the possible data type mismatch errors.
string conS ="..."; // connection string
var param = 1;
using (var connection = new OleDbConnection(conS))
{
string queryString = "SELECT stockName FROM Stock WHERE stockLowCalculation < #var"
var cmd = new OleDbCommand(queryString, connection);
cmd.Parameters.Add(new OleDbParameter("#var", param));
connection.Open();
OleDbDataAdapter adapt = new OleDbDataAdapter(cmd);
}

Fetching data for particular Month and year

I tried Query(given below in code) But it is showing me this error
No value given for one or more required parameters.
but while debugging I am passing date as this
string monthYY = dateTimePickerMonth.Value.ToString("M-yy");
So what is the right format to check it ,how can I do it ?
Code for Query
public int GetDrID_MonthWise(string DrName,string monthYY,int refDrID)
{
int data = 0;
try
{
string sql = "Select d.DoctorID From Doctor_Master d where d.LastName + ' ' + d.FirstName = '" + DrName + "' AND Patient_registration.RegDate='" + monthYY + "' AND Patient_registration.DoctorID=" + refDrID;
cmd = new OleDbCommand(sql, acccon);
rs = cmd.ExecuteReader();
while (rs.Read())
{
data = Convert.ToInt32(rs[0]);
}
}
catch (Exception err)
{
MessageBox.Show(err.Message.ToString());
}
return data;
}
This piece of your SQL statement informs the db engine Doctor_Master is the data source:
From Doctor_Master d
However, the WHERE clause refers to 2 fields which are not present in Doctor_Master:
Patient_registration.RegDate
Patient_registration.DoctorID
I'm unsure what you actually need. My hunch is you should INNER JOIN those tables. But I think you should design and test the query in Access, leaving c# out of the picture until after you have the Access query working as you wish.
I'm not sure exactly how you are passing your parameters but you need to specify values for all three of your parameters listed
public int GetDrID_MonthWise(string DrName,string monthYY,int refDrID)

ExecuteScalar always returns 0

I'm not sure why this is happening. I've seen the same issue online with little help out there to correct it.
When i run my query inside Access i get different values ranging from 0 - 10 but for some reason, it won't return that same value inside my code.
static int OrdersPerHour(string User)
{
int? OrdersPerHour = 0;
OleDbConnection conn = new OleDbConnection(strAccessConn);
DateTime curTime = DateTime.Now;
try
{
string query = "SELECT COUNT(ControlNumber) FROM Log WHERE DateChanged > #" + curTime.AddHours(-1) + "# AND User = '" + User + "' AND Log.EndStatus in ('Needs Review', 'Check Search', 'Vision Delivery', 'CA Review', '1TSI To Be Delivered');";
OleDbCommand dbcommand = new OleDbCommand(query, conn);
dbcommand.Connection.Open();
dbcommand.CommandType = CommandType.Text;
dbcommand.CommandText = query;
OrdersPerHour = (int?)dbcommand.ExecuteScalar();
}
catch (OleDbException ex)
{
}
finally
{
conn.Close();
}
return OrdersPerHour.Value;
}
Do not use string concatenation and the Access syntax to build your sql commands.
Use a simple parameterized query like this
string query = "SELECT COUNT(ControlNumber) FROM Log " +
"WHERE DateChanged > ? AND [User] = ? AND " +
"Log.EndStatus in ('Needs Review', 'Check Search', 'Vision Delivery'," +
"'CA Review', '1TSI To Be Delivered');";
OleDbCommand dbcommand = new OleDbCommand(query, conn);
dbcommand.Parameters.AddWithValue("#p1", curTime.AddHours(-1));
dbcommand.Parameters.AddWithValue("#p2", User);
dbcommand.Connection.Open();
dbcommand.CommandType = CommandType.Text;
OrdersPerHour = (int)dbcommand.ExecuteScalar();
In this way the burden to correctly interpret your value is passed to the Framework code that could format dates, decimals and strings according to your database requirements. By the way this will also prevent Sql Injection
Also, the word USER is a reserved keyword in Access SQL and thus you need to encapsulate it with square brackets
First and most important: Use Parametrized Queries!
Regarding your problem, I suggest you to debug the code:
Get the Commandtext of your "OleDbCommand dbcommand" and manually query to see if you get the same result.
Also, you should put your code within the try catch block, else it does not make sense at all.

Updating MySql counter when users log in

I have a website where users can log in. The client wants there to be a way to record the number of times any particular user logs in. I have a "Counter" row in the table. How do I program the app (built in C# ASP.NET) to update the counter when people log in? Is this code correct:
cmd.ExecuteNonQuery = "UPDATE Counter FROM brokercenter"
I just recently graduated (as in the 10th of this month) so I am new to this, plus I know nothing about databases, I am just learning on the job. Please let me know if I need any other parameter or connection string or aything else? This is in the button click event and there is already a connection string there to check the username and password so I don't think I need another connection string, but I don;t know for sure. Thanks in advance!
For that matter, here is the whole event (the login stuff works fine, just the update is my question):
string connectionString =
ConfigurationManager.ConnectionStrings["moverschoiceConnectionString"].ConnectionString;
OdbcConnection conn = new OdbcConnection(connectionString);
conn.Open(); OdbcCommand cmd = new OdbcCommand();
cmd.Connection = conn;
cmd.CommandText = "select Email, Password from brokercenter where Email = '" + txtLoginEmail.Text + "'";
OdbcDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
if (reader["Password"].ToString() == txtLoginPassword.Text)
{
reader.Close();
if (cbRememberMe.Checked == true)
{
Response.Cookies["username"].Value = txtLoginEmail.Text;
Response.Cookies["username"].Expires = DateTime.Now.AddMonths(1);
Response.Cookies["password"].Value = txtLoginPassword.Text;
Response.Cookies["password"].Expires = DateTime.Now.AddMonths(1);
}
else
{
Response.Cookies["username"].Expires = DateTime.Now.AddMonths(-1);
Response.Cookies["password"].Expires = DateTime.Now.AddMonths(-1);
}
Response.Redirect("BrokerResources.aspx");
}
else
{
lblLoginError.Text = "Invalid Password";
}
}
lblLoginError.Text = "Invalid Email or Password";
reader.Close();
cmd.ExecuteNonQuery = "UPDATE counter FROM brokercenter";
}
For a start, you should read about using UPDATE in MySQL's Reference Manual.
There is even an example for exactly what you want to do.
Quote from the link:
If you access a column from the table to be updated in an expression,
UPDATE uses the current value of the column. For example, the
following statement sets col1 to one more than its current value:
UPDATE t1 SET col1 = col1 + 1;
This is basically all you need, you just need to add a WHERE clause and filter for the username or for the email.
Plus, you should read about SQL Injection because of this:
where Email = '" + txtLoginEmail.Text + "'";
Concatenating strings like this to pass parameters can cause problems as described in the link.
Here's an example how to do it better.
cmd.ExecuteNonQuery = String.Format("UPDATE brokercenter SET counter = {0} WHERE Email = {1}", myCounter++, txtLoginEmail.Text);
where "myCounter" is a local counter variable (which should also be read from the database). Does this make sense now?

Categories

Resources