SQLCommand syntax error - c#

I am writing to request some help on my c# syntax. I keep getting syntax in "sda.Fill(dt);" and I can not figure out the reason why.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string query = "select distinct Price_type from Price";
DataTable dt = GetData(query);
ddlPrice.DataSource = dt;
ddlPrice.DataTextField = "Price_type";
ddlPrice.DataValueField = "Price_type";
ddlPrice.DataBind();
ddlPrice2.DataSource = dt;
ddlPrice2.DataTextField = "Price_type";
ddlPrice2.DataValueField = "Price_type";
ddlPrice2.DataBind();
ddlPrice2.Items[1].Selected = true;
}
}
protected void Compare(object sender, EventArgs e)
{
string query = string.Format("select price, date from Price where Price_type = '{0}' order by date)", ddlPrice.SelectedItem.Value);
DataTable dt = GetData(query);
string[] x = new string[dt.Rows.Count];
decimal[] y = new decimal[dt.Rows.Count];
for (int i = 0; i < dt.Rows.Count; i++)
{
x[i] = dt.Rows[i][0].ToString();
y[i] = Convert.ToInt32(dt.Rows[i][1]);
}
LineChart1.Series.Add(new AjaxControlToolkit.LineChartSeries { Name = ddlPrice.SelectedItem.Value, Data = y });
query = string.Format("select price, date from Price where Price_type = '{0}' order by date)", ddlPrice2.SelectedItem.Value);
dt = GetData(query);
y = new decimal[dt.Rows.Count];
for (int i = 0; i < dt.Rows.Count; i++)
{
x[i] = dt.Rows[i][0].ToString();
y[i] = Convert.ToInt32(dt.Rows[i][1]);
}
LineChart1.Series.Add(new AjaxControlToolkit.LineChartSeries { Name = ddlPrice2.SelectedItem.Value, Data = y });
LineChart1.CategoriesAxis = string.Join(",", x);
LineChart1.ChartTitle = string.Format("{0} and {1} Order Distribution", ddlPrice.SelectedItem.Value, ddlPrice2.SelectedItem.Value);
LineChart1.Visible = true;
}
private static DataTable GetData(string query)
{
DataTable dt = new DataTable();
string constr = ConfigurationManager.ConnectionStrings["bwic testConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(query))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
sda.SelectCommand = cmd;
sda.Fill(dt);
}
}
return dt;
}
}

date might be a reserved keyword, depending of the version you use. Write [date] instead. And this
"select price, date from Price where Price_type = '{0}' order by date)"
should be
"select price, date from Price where Price_type = '{0}' order by date"

You can try with this code
using (var con = new SqlConnection(constr))
{
using (var cmd = new SqlCommand(query))
{
using (var sda = new SqlDataAdapter())
{
con.Open();
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
sda.SelectCommand = cmd;
sda.Fill(dt);
}
}
return dt;
}

There's nothing syntactically wrong with your GetData() method as shown in your original post. You might try commenting out the entire body of the method and then start uncommenting things one at a time to isolate the actual problem.
But it apparently seems that you don't have a syntax error: you have invalid SQL. The SQL you are trying to execute is:
select price, date from Price where Price_type = '{0}' order by date)
It has two things wrong with it:
The closing (right) parenthesis at the end is your syntax error, and
the parameter should not be enclosed in quotes.
Your SQL should look something like
select price, date from Price where Price_type = {0} order by date
Your method should look something like this:
private static DataTable GetData1( string query , string p0 )
{
DataTable dt = new DataTable();
string constr = ConfigurationManager.ConnectionStrings["bwic testConnectionString"].ConnectionString;
using ( SqlConnection con = new SqlConnection( constr ) )
using ( SqlCommand cmd = con.CreateCommand() )
using ( SqlDataAdapter sda = new SqlDataAdapter(cmd) )
{
cmd.CommandText = query;
cmd.CommandType = CommandType.Text;
SqlParameter p = new SqlParameter() ;
p.Value = p0Value ;
cmd.Parameters.Add( p ) ;
con.Open();
sda.Fill( dt );
con.Close();
}
return dt;
}

Don't forget to use brackets twice - in SELECT clause and in ORDER BY clause too.

in your code bolck as below
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(query))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
sda.SelectCommand = cmd;
sda.Fill(dt);
}
}
return dt;
}
change it to
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(query))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
con.Open();
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
sda.SelectCommand = cmd;
sda.Fill(dt);
}
}
return dt;
}
The problem here is that you havent opened any connection before filling.

You haven't opened a connection anywhere. You must open the connection before you can use it.

If your whole class code is really this, you are missing a closing } at the end of the file for the
public partial class Default2 : System.Web.UI.Page
{
declaration.

Related

How to store multiple SQL data columns into different variables C#

I am trying to store sql data that I have for a voucher id and voucher amount into a variable and display it into a label on a click of a button.
protected void Button1_Click(object sender, EventArgs e)
{
string voucherId = String.Empty;
string voucherAmount = String.Empty;
string queryVoucherId = "select voucherid from ReturnForm where email = '" + Session["username"] + "';";
string queryVoucherAmount = "select voucheramount from ReturnForm where email = '" + Session["username"] + "';";
int index = 0;
using (SqlConnection con = new SqlConnection(str))
{
SqlCommand cmd = new SqlCommand(queryVoucherId, con);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
voucherId = reader[index].ToString();
index++;
}
}
using (SqlConnection con = new SqlConnection(str))
{
SqlCommand cmd = new SqlCommand(queryVoucherAmount, con);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
voucherAmount = reader[index].ToString();
index++;
}
}
if (txtVoucher.Text == voucherId)
{
Label3.Visible = true;
Label3.Text = voucherAmount;
}
}
When I click the button its giving me an error saying that the index is out of bounds.
Building on #JSGarcia's answer - but using parameters as one ALWAYS should - you'd get this code:
string email = Session['username'];
string query = $"SELECT voucherid, voucheramount FROM ReturnFrom WHERE Email = #email";
DataTable dt = new DataTable();
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(query, conn))
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
// set the parameter before opening connection
// this also defines the type and length of parameter - just a guess here, might need to change this
cmd.Parameters.Add("#email", SqlDbType.VarChar, 100).Value = email;
conn.Open();
sda.Fill(dt);
conn.Close();
}
Personally, I'd rather use a data class like
public class VoucherData
{
public int Id { get; set; }
public Decimal Amount { get; set; }
}
and then get back a List<VoucherData> from your SQL query (using e.g. Dapper):
string query = $"SELECT Id, Amount FROM ReturnFrom WHERE Email = #email";
List<VoucherData> vouchers = conn.Query<VoucherData>(query).ToList();
I'd try to avoid the rather clunky and not very easy to use DataTable construct...
I strongly recommend combining your sql queries into a single one, write it into a datatable and continue your logic from there. IMHO it is much cleaner code:
string email = Session['username'];
string query = $"SELECT voucherid, voucheramount FROM ReturnFrom where Email = '{email}'";
DataTable dt = new DataTable();
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = conn.CreateCommand())
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
cmd.CommandText = query;
cmd.CommandType = CommandType.Text;
conn.Open();
sda.Fill(dt);
conn.Close();
}
// Work with DataTable dt from here on
...
Well, one more big tip?
You ONLY as a general rule need a dataadaptor if you going to update the data table.
And you ONLY need a new connection object if you say not using the sql command object.
The sqlcommand object has:
a connection object - no need to create a separate one
a reader - no need to create a separate one.
Note how I did NOT create a seperate connection object, but used the one built into the command object.
And since the parameter is the SAME in both cases? Then why not re-use that too!!
So, we get this:
void TestFun2()
{
String str = "some conneciton???";
DataTable rstVouch = new DataTable();
using (SqlCommand cmdSQL =
new SqlCommand("select voucherid from ReturnForm where email = #email",
new SqlConnection(str)))
{
cmdSQL.Parameters.Add("#email", SqlDbType.NVarChar).Value = Session["username"];
cmdSQL.Connection.Open();
rstVouch.Load(cmdSQL.ExecuteReader());
// now get vouch amount
cmdSQL.CommandText = "select voucheramount from ReturnForm where email = #email";
DataTable rstVouchAmount = new DataTable();
rstVouchAmount.Load(cmdSQL.ExecuteReader());
if (rstVouch.Rows[0]["vourcherid"].ToString() == txtVoucher.Text)
{
Label3.Visible = true;
Label3.Text = rstVouchAmount.Rows[0]["voucheramount"].ToString();
}
}
}

C# Paginate SQL result from a proc call

I have the following method that calls a proc in my database and returns the results into a dataset. The dataset is then used to populate a table I render using MVC & cshtml.
The method is:
public DataSet CallProcToDataSet(string procName)
{
DataSet ds = new DataSet();
string constr = ConfigurationManager.ConnectionStrings["UAT"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(procName))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
sda.Fill(ds);
}
}
}
return ds;
}
This works fine, however what I want is to have some way of paginating the results so that only 10 at a time are displayed. What is the best way for me to achieve this that doesn't involve any changes to the proc calls?
You can use this overload of the Fill method
public int Fill(int startRecord, int maxRecords, params DataTable[] dataTables);
(link: https://msdn.microsoft.com/en-us/library/0z5wy74x(v=vs.110).aspx)
This way you will only return a subset of the records without modifying your stored procedure.
Example (MSTest)
[TestMethod]
public void TestMethod1()
{
DataSet ds = new DataSet();
var procName = "sp_server_info";
string constr = ConfigurationManager.ConnectionStrings["UAT"].ConnectionString;
var tblName = "result";
var tbls = new[] { ds.Tables.Add(tblName) };
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(procName))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
sda.Fill(0, 10, tbls);
}
}
}
Assert.AreEqual(tbls[0].Rows.Count, 10);
}
Try following :
DataSet ds = new DataSet();
DataTable dt = ds.Tables[0];
for (int i = 0; i < dt.Rows.Count; i += 10)
{
DataTable pageTable = dt.AsEnumerable().Where((x, n) => (n >= i) && (n < i + 10)).CopyToDataTable();
}

Can't retrieve data from database and store into a value

I am currently working on a forum project using a gridview to attached the data to the database. Using SelectedIndexChanged, it will redirect to another page to display the details in labels. However, I am unable to display & there isn't any specific error.
This is my code:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class FAQViewPost : System.Web.UI.Page
{
string _connStr = ConfigurationManager.ConnectionStrings["WingsDrinksDbContext"].ConnectionString;
FAQ faq = null;
string CustQuestionCategory = null;
string CustQuestion = null;
protected void Page_Load(object sender, EventArgs e)
{
string FAQID = Request.QueryString["FAQID"].ToString();
Load(FAQID);
}
protected void Load(string FAQID)
{
DataTable dt = new DataTable();
string queryStr = "SELECT * FROM [FAQ] WHERE FAQID = #FAQID ";
SqlConnection conn = new SqlConnection(_connStr);
SqlCommand cmd = new SqlCommand();
string[] arr = { queryStr };
string allQueries = string.Join(";", arr);
cmd.CommandText = allQueries;
cmd.Connection = conn;
cmd.Parameters.AddWithValue("#FAQID", FAQID);
SqlDataAdapter sqlDa = new SqlDataAdapter(cmd);
sqlDa.Fill(dt);
if (dt.Rows.Count > 0)
{
lbl_category.Text = dt.Rows[0]["CustQuestionCategory"].ToString();
lbl_question.Text = dt.Rows[0]["CustQuestion"].ToString();
}
conn.Close();
conn.Dispose();
}
}
I do not know why you are putting the SQL into an array. You only have one statement. Try using just:
DataTable dt = new DataTable();
string queryStr = "SELECT * FROM [FAQ] WHERE FAQID = #FAQID ";
SqlConnection conn = new SqlConnection(_connStr);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = queryStr;
cmd.Connection = conn;
cmd.Parameters.AddWithValue("#FAQID", FAQID);
SqlDataAdapter sqlDa = new SqlDataAdapter(cmd);
sqlDa.Fill(dt);
I presume you have checked that the FAQ table has a record for the id you are sending? Also life would be a bit safer if you used numeric ids.

Set datatables to be equivalent

This is probably a simple question but I am not experienced in C#.
I have 2 datatables, 1 is basically a copy of the other (like a table to review information). To set the values this is what I am doing now:
string attribute1 = "";
string attribute2 = "";
string attribute3 = "";
.....
DataTable result = new DataTable();
using (SqlConnection con = new SqlConnection("user id=user_id;password=pwd;server=serverstring;Trusted_Connection=yes;database=database;connection timeout=30"))
{
using (SqlCommand cmd = new SqlCommand("SELECT * FROM table1 WHERE parameter=#identifying_parameter", con))
{
cmd.Parameters.AddWithValue("#identifying_parameter", "example");
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
attribute1 = Convert.ToString(reader["attribute1"]);
attribute2 = Convert.ToString(reader["attribute2"]);
attribute3 = Convert.ToString(reader["attribute3"]);
.....
}
con.Close();
}
}
using (SqlConnection con = new SqlConnection("user id=user_2;password=pwd;server=serverstring;Trusted_Connection=yes;database=database;connection timeout=30"))
{
using (SqlCommand cmd = new SqlCommand("INSERT INTO table2 (attribute1, attribute2, attribute3, ...) VALUES(#attribute1, #attribute2, #attribute3, ...)", con))
{
cmd.Parameters.AddWithValue("#attribute1", attribute1);
cmd.Parameters.AddWithValue("#attribute2", attribute2);
cmd.Parameters.AddWithValue("#attribute3", attribute3);
....
con.Open();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(result);
con.Close();
da.Dispose();
}
}
Obviously I might have a lot of attributes, so is there a simpler way to set every attribute in the table to be equal in C#?
You can use INSERT..INTO..SELECT
DataTable result = new DataTable();
using (SqlConnection con = new SqlConnection("user id=user_2;password=pwd;server=serverstring;Trusted_Connection=yes;database=database;connection timeout=30"))
{
using (SqlCommand cmd = new SqlCommand(#"INSERT INTO table2 (attribute1, attribute2, attribute3, ...)
SELECT attribute1, attribute2, attribute3 ... FROM table1
WHERE parameter=#identifying_parameter
", con))
{
cmd.Parameters.AddWithValue("#identifying_parameter", "example");
con.Open();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(result);
con.Close();
da.Dispose();
}
}
You can use * instead of specifying the column name, although which is not good practice..
In order to make a second Table identical (or "equivalent" as per your definition) to the first one (for certainty let's call it sourceTable), you can use SqlBulkCopy.WriteToServer Method (DataTable)(re: https://msdn.microsoft.com/en-us/library/ex21zs8x%28v=vs.110%29.aspx)
using (SqlConnection YourConnection= new SqlConnection(YourConnectionString))
{
YourConnection.Open();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(YourConnection))
{
bulkCopy.DestinationTableName = "dbo.YourDestinationTable";
try
{
// Write from the source to the destination.
bulkCopy.WriteToServer(sourceTable);
}
catch (Exception ex) { }
}
}
In order to get a sourceTable you can use the following code snippet:
DataTable sourceTable = SqlReadDB(YourConnString, "SELECT *")
private static DataTable SqlReadDB(string ConnString, string SQL)
{
DataTable _dt;
try
{
using (SqlConnection _connSql = new SqlConnection(ConnString))
{
using (SqlCommand _commandl = new SqlCommand(SQL, _connSql))
{
_commandSql.CommandType = CommandType.Text;
_connSql.Open();
using (SqlCeDataReader _dataReaderSql = _commandSql.ExecuteReader(CommandBehavior.CloseConnection))
{
_dt = new DataTable();
_dt.Load(_dataReaderSqlCe);
_dataReaderSql.Close();
}
}
_connSqlCe.Close();
return _dt;
}
}
catch { return null; }
}
}
Hope this may help.

Must declare a scalar variable.?

I have to display bar chart using ajax extender tool. I have to display information on chart when I am selecting one value from drop down list. But it shows "Must declare a scalar variable" error. Please help me.
Code:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string query = "select Name from aTable";
DataTable dt = GetData(query);
ddlCountries.DataSource = dt;
ddlCountries.DataTextField = "Name";
ddlCountries.DataValueField = "Name";
ddlCountries.DataBind();
ddlCountries.Items.Insert(0, new ListItem("Select", ""));
}
}
private DataTable GetData(string query)
{
DataTable dt = new DataTable();
string constr = ConfigurationManager.ConnectionStrings["demoConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(query))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
sda.SelectCommand = cmd;
sda.Fill(dt);
}
}
return dt;
}
}
protected void ddlCountries_SelectedIndexChanged(object sender, EventArgs e)
{
string query = string.Format("select Debit, Credit, Year From aTable where Name=#Name", ddlCountries.SelectedItem.Value);
DataTable dt = GetData(query);
string[] x = new string[dt.Rows.Count];
decimal[] y = new decimal[dt.Rows.Count];
for (int i = 0; i < dt.Rows.Count; i++)
{
x[i] = dt.Rows[i][0].ToString();
y[i] = Convert.ToInt32(dt.Rows[i][1]);
}
BarChart1.Series.Add(new AjaxControlToolkit.BarChartSeries { Data = y });
BarChart1.CategoriesAxis = string.Join(",", x);
BarChart1.ChartTitle = string.Format("{0} Order Distribution", ddlCountries.SelectedItem.Value);
if (x.Length > 3)
{
BarChart1.ChartWidth = (x.Length * 100).ToString();
}
BarChart1.Visible = ddlCountries.SelectedItem.Value != "";
}
In this line
string query = string.Format(#"select Debit, Credit, Year
From aTable where Name=#Name",
ddlCountries.SelectedItem.Value);
you have a parameter placeholder #Name but you don't add the required parameter to the SqlCommand that executes the sql. This produces the error that you see.
(By The way, string.Format requires the placeholder in the form {0}, but also if you fix that problem it is still wrong because you leave open the door to Sql Injection)
Fixing it requires a change in your GetData function.
You need to add an (optional) parameter array as another argument
private DataTable GetData(string query, SqlParameter[] prms = null)
{
DataTable dt = new DataTable();
string constr = ConfigurationManager.ConnectionStrings["demoConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(query))
{
if(prms != null)
cmd.Parameters.AddRange(prms);
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
sda.SelectCommand = cmd;
sda.Fill(dt);
}
}
return dt;
}
}
And now, when you call that method, you could write
string query = "select Debit, Credit, [Year] From aTable where Name=#Name";
SqlParameter[] prms = new SqlParameter[1];
prms[0] = new SqlParameter("#Name", SqlDbType.NVarChar).Value =
ddlCountries.SelectedItem.Value.ToString());
DataTable dt = GetData(query, prms);
Notice also that I have put the field Year between square brackets. Year is the name of a T-SQL Function and you should use this trick to avoid to confuse the SQL Parser

Categories

Resources