Is it possible to use OleDBCommand parameters elsewhere than the Where clause? - c#

I have this code:
using (OleDbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = string.Format(
#"SELECT TOP {0} t_accounts.account_no as AccountID, IIF(ISNULL(t_accounts.name),'[blank]',t_accounts.name) AS Name
FROM t_accounts
INNER JOIN td_department_accounts ON (t_accounts.account_no = td_department_accounts.account_no)
WHERE (AccountID >= #firstId) AND type = 'DE'", CountToFetch);
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#firstId", FirstId);
...but wonder if I could use a param for the top count too, like:
using (OleDbCommand cmd = conn.CreateCommand())
{
cmd.CommandText =
#"SELECT TOP #count t_accounts.account_no as AccountID, IIF(ISNULL(t_accounts.name),'[blank]',t_accounts.name) AS Name
FROM t_accounts
INNER JOIN td_department_accounts ON (t_accounts.account_no = td_department_accounts.account_no)
WHERE (AccountID >= #firstId) AND type = 'DE'";
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#firstId", FirstId);
cmd.Parameters.AddWithValue("#count", CountToFetch);
...or are database params limited to the WHERE clause only?
UPDATE
With this code:
cmd.CommandText =
#"SELECT TOP #countToFetch t_accounts.account_no as AccountID,
IIF(ISNULL(t_accounts.name),'[blank]',t_accounts.name) AS Name
FROM t_accounts
INNER JOIN td_department_accounts ON (t_accounts.account_no =
td_department_accounts.account_no)
WHERE (AccountID >= #firstId) AND type = 'DE'";
. . .
cmd.Parameters.AddWithValue("#firstId", FirstId);
cmd.Parameters.AddWithValue("#countToFetch", CountToFetch);
...I got, "The SELECT statement includes a reserved word or an argument name that is misspelled or missing, or the punctuation is incorrect."
So I reverted back to:
cmd.CommandText = string.Format(
#"SELECT TOP {0} t_accounts.account_no as AccountID,
IIF(ISNULL(t_accounts.name),'[blank]',t_accounts.name) AS Name
FROM t_accounts
INNER JOIN td_department_accounts ON (t_accounts.account_no =
td_department_accounts.account_no)
WHERE (AccountID >= #firstId) AND type = 'DE'", CountToFetch);
. . .
cmd.Parameters.AddWithValue("#firstId", FirstId);
UPDATE 2
This:
SELECT TOP (#countToFetch) t_accounts.account_no as AccountID, IIF(ISNULL
(t_accounts.name),'[blank]',t_accounts.name) AS Name
FROM t_accounts
INNER JOIN td_department_accounts ON (t_accounts.account_no = td_department_accounts.account_no)
WHERE (AccountID >= #firstId) AND type = 'DE'"
...in Access tells me "The SELECT statement includes a reserved word or an argument name that is misspelled or missing, or the punctuation is incorrect."
NOTE: Postman tells me the exact same thing when making the REST call that ends up with the making of that query.
UPDATE 3
I also tried it as in Update 2 but with ":" instead of "#" and this way:
SELECT TOP (?) t_accounts.account_no as AccountID, IIF(ISNULL(t_accounts.name),'[blank]',t_accounts.name) AS Name
FROM t_accounts
INNER JOIN td_department_accounts ON (t_accounts.account_no = td_department_accounts.account_no)
WHERE (AccountID >= ?) AND type = 'DE'"

I came across this post that seems to indicate that this does work, at least with T-SQL. I'm inclined to assume, given that, that it works with Access. Just, as that says, remember to include parentheses.
In any event, it's definitely not true that parameters can only be in the WHERE clause. You can use them in the SELECT, or even the ORDER BY.

Related

Record count in c# query result

How can i get Total records count in query result
SqlConnection con1 = new SqlConnection(ConfigurationManager.ConnectionStrings["con1"].ConnectionString);
string sql = "select Fare , OrderAmount FROM orderitems OI INNER JOIN Orders O ON O.OrderID = OI.OrderID WHERE PaymentStatusID = 1 AND o.orderid ="+Orderid;
SqlCommand comd = new SqlCommand(sql, con1);
con1.Open();
comd.ExecuteNonQuery();
Above is my sql query i need result count, can some one help me
Thanks in advance.
ExecuteNonQuery is used for query like insert/update/delete.
Use ExecuteScalar instead:
string sql = "select count(*) FROM orderitems OI INNER JOIN Orders O ON O.OrderID = OI.OrderID WHERE PaymentStatusID = 1 AND o.orderid ="+Orderid;
SqlCommand comd = new SqlCommand(sql, con1);
con1.Open();
int count = Convert.ToInt32(comd.ExecuteScalar());
If you don't need the Fare and the OrderAmount (a bit strange, since the sql script you have written contains them), you could replace them with a COUNT(*).
string sql = "select COUNT(*) FROM orderitems OI INNER JOIN Orders O ON O.OrderID = OI.OrderID WHERE PaymentStatusID = 1 AND o.orderid ="+Orderid;
Then you can read this fairly easily, like below:
int numberOfRecords = Convert.ToInt32(comd.ExecuteScalar());
On the other hand, if you need them, you could count the number of records in the sql reader you will use to read those results, like below:
SqlDataReader sqlReader = comd.ExecuteReader();
int numberOfRecords = 0;
while(sqlReader.Read())
{
// do things
numberOfRecords++;
}
Note
In any case, you can't use the ExecuteNonQuery method, since you want to read something from a database. You don't want to create, update or delete something. Only in the latter cases we use this method.
One more important note is about the security of the queries you build and then execute is to avoid string concatenation for passing the values of parameters. This makes your app vulnerable to sql injections, one of the major ways of attacks. Instead of doing this, you could use a sql parametrized query, like below:
string sql = "select Fare , OrderAmount FROM orderitems OI INNER JOIN Orders O ON O.OrderID = OI.OrderID WHERE PaymentStatusID = 1 AND o.orderid=#Orderid";
SqlCommand cmd = new SqlCommand(sql, con1);
cmd.Parameters.Add("#Orderid",OrderId);

Valid SQL Statement Returning 'Syntax Error" in Asp.NET

I'm making an ASP.Net web application, but it is returning a syntax error whenever I try to load the page.
My DB schema can be seen here http://sqlfiddle.com/#!2/739c4/7
Here is the SQL query:
SELECT
tblOrderTransactions.ordertransaction_orderid AS orderid,
tblProducts.product_name AS productname,
tblOrders.order_customer AS ordercustomer
FROM
tblProducts
LEFT JOIN tblOrderTransactions
ON tblProducts.product_id = tblOrderTransactions.ordertransaction_productid
LEFT JOIN tblOrders
ON tblOrderTransactions.ordertransaction_orderid = tblOrders.order_id
WHERE
(
(
(
tblOrderTransactions.ordertransaction_orderid
)
=3
)
) and (
(
(tblOrders.order_customer)
=3
)
)
The SQL works in sqlfiddle, and if I remove the part that says
LEFT JOIN tblOrders
ON tblOrderTransactions.ordertransaction_orderid = tblOrders.order_id
in my web application, the table loads. Adding this second INNER JOIN seems to be messing it up, but the same query works in sqlfiddle, so I believe the SQL is correct.
The error message I receive is
Syntax error (missing operator) in query expression 'tblProducts.product_id = tblOrderTransactions.ordertransaction_productid LEFT JOIN tblOrders ON tblOrderTransactions.ordertransaction_orderid = tblOrders.order_i'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.OleDb.OleDbException: Syntax error (missing operator) in query expression 'tblProducts.product_id = tblOrderTransactions.ordertransaction_productid LEFT JOIN tblOrders ON tblOrderTransactions.ordertransaction_orderid = tblOrders.order_i'.
C# Code inside the application:
string orderID = Request.QueryString["id"];
OleDbConnection conn = new OleDbConnection();
conn.ConnectionString = ConfigurationManager.ConnectionStrings["finalConnString"].ConnectionString;
string commText = #"SELECT tblOrderTransactions.ordertransaction_orderid AS orderid, tblProducts.product_name AS productname
FROM tblProducts
LEFT JOIN tblOrderTransactions
ON tblProducts.product_id = tblOrderTransactions.ordertransaction_productid
LEFT JOIN tblOrders
ON tblOrderTransactions.ordertransaction_orderid = tblOrders.order_id
WHERE (((tblOrderTransactions.ordertransaction_orderid)=?)) ";
conn.Open();
OleDbCommand comm = conn.CreateCommand();
comm.Connection = conn;
comm.CommandText = commText;
OleDbParameter param;
param = comm.CreateParameter();
param.DbType = DbType.Int32;
param.Direction = ParameterDirection.Input;
param.Value = Int32.Parse(orderID);
comm.Parameters.Add(param);
//param = comm.CreateParameter();
//param.DbType = DbType.Int32;
//param.Direction = ParameterDirection.Input;
//param.Value = Session["LoggedInId"];
//comm.Parameters.Add(param);
OleDbDataReader reader = comm.ExecuteReader();
if (reader.HasRows)
{
rptOrders.DataSource = reader;
rptOrders.DataBind();
lblOrderNumber.Text = orderID.ToString();
}
else
{
Response.Write("You are not authorized to view this order.");
}
//Free up the connection
conn.Close();
The SQL Statement must have the joins nested in parentheses because of Access specific syntax (Thank you #MattiVirkkunen for that knowledge).
The correct way to write this SQL statement is:
SELECT tblOrderTransactions.ordertransaction_orderid, tblProducts.product_name, tblOrders.order_customer
FROM tblProducts
INNER JOIN (tblOrders
INNER JOIN tblOrderTransactions
ON tblOrders.[order_id] = tblOrderTransactions.[ordertransaction_orderid])
ON tblProducts.[product_id] = tblOrderTransactions.[ordertransaction_productid]
WHERE (((tblOrderTransactions.ordertransaction_orderid)=3)) and (((tblOrders.order_customer)=3))
First, I would suggest working with aliases to keep your query a little shorter to read (and type) such as below.
SELECT
OT.ordertransaction_orderid AS orderid,
P.product_name AS productname,
O.order_customer AS ordercustomer
FROM
tblProducts P
LEFT JOIN tblOrderTransactions OT
ON P.product_id = OT.ordertransaction_productid
LEFT JOIN tblOrders
ON OT.ordertransaction_orderid = O.order_id
WHERE
OT.ordertransaction_orderid = 3
and O.order_customer = 3
Second, it does look completely legit and nothing glaring out as invalid. But error of loading the page MIGHT be due to no records being returned. You have your query with left-joins, but then throwing in your WHERE clause for both the "tblOrderTransactions" and "tblOrders" tables changes it to an INNER JOIN result.
So, your query looking for order ID = 3 and also the customer = 3, what if that was not the case, that order #3 was customer #1 which would result in NO RECORDS.
Getting back to now seeing your posted syntax, it looks unbalanced parens ((( )) that might be the issue.
And a final review.. Your "ID" from the query string. Is it properly doing an int.Parse() against it? I know on some instances of int.parse() I've done in the past, if the string started with a space vs actual number, int.Parse() would throw an error... Confirm the incoming values and did it really convert as you expected.

C# SqlCommand is not sending the right query with parameters

It's a pretty simple problem, but I can't find a solution (not even sure what question to google here).
Here is my code to create the command:
var targetStartDate = "October 2014";//ConfigurationManager.AppSettings["StartDateString"].ToString(CultureInfo.InvariantCulture);
var acceptedStatusCodes = 4;//ConfigurationManager.AppSettings["ImportStatusIds"].ToString(CultureInfo.InvariantCulture);
using (var connection = new SqlConnection(connString))
{
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = #"
SELECT
ai.FirstName,
ai.LastName,
ai.Email,
ai.SSN,
ai.Phone,
ai.Program,
r.FirstName + ' ' + r.LastName AS RepName,
d.Name AS StartDateName,
s.CvId AS CvSySchoolStatusId,
ai.CampusId as SyStudentId
FROM
dbo.aspnet_Users AS u LEFT OUTER JOIN
dbo.ApplicantInfo AS ai ON u.UserId = ai.UserId LEFT OUTER JOIN
dbo.AdmissionReps AS r ON ai.AdmissionsRepId = r.RepId LEFT OUTER JOIN
dbo.ProgramStartDate AS d ON ai.StartDateId = d.CvStartDateId LEFT OUTER JOIN
dbo.CvSySchoolStatus AS s ON ai.CvSySchoolStatusId = s.CvId
where d.Name = '#StartDate'
and CvSySchoolStatusId in (#Statuses)";
cmd.Parameters.AddWithValue("#StartDate", SqlDbType.VarChar).Value = (object) targetStartDate;
cmd.Parameters.AddWithValue("#Statuses", SqlDbType.Int).Value = (object) acceptedStatusCodes;
...
}
....
}
The reader sends the command fine, I can see it go through via SQL profiler:
exec sp_executesql N'
SELECT
ai.FirstName,
ai.LastName,
ai.Email,
ai.SSN,
ai.Phone,
ai.Program,
r.FirstName + '' '' + r.LastName AS RepName,
d.Name AS StartDateName,
s.CvId AS CvSySchoolStatusId,
ai.CampusId as SyStudentId
FROM
dbo.aspnet_Users AS u LEFT OUTER JOIN
dbo.ApplicantInfo AS ai ON u.UserId = ai.UserId LEFT OUTER JOIN
dbo.AdmissionReps AS r ON ai.AdmissionsRepId = r.RepId LEFT OUTER JOIN
dbo.ProgramStartDate AS d ON ai.StartDateId = d.CvStartDateId LEFT OUTER JOIN
dbo.CvSySchoolStatus AS s ON ai.CvSySchoolStatusId = s.CvId
where d.Name = ''#StartDate''
and CvSySchoolStatusId in (#Statuses)'
,N'#StartDate nvarchar(12),#Statuses int'
,#StartDate=N'October 2014'
,#Statuses=4
This query gives me 0 results, but if I take this exact query and just paste in the parameters and run just the query text, I get the expected results. Any idea where I am going wrong here?
You need to remove single quotes around your parameter in string query
this:
where d.Name = '#StartDate'
should be:
where d.Name = #StartDate
No single parameters.
Perhaps it's the extra single quotes around startdate. I think you might want to remove those single quotes and try again. Should look like:
...
where d.Name = #StartDate

Select more columns with MAX function in SQLCE

Need to find max value of id, and by this value I need to read value of others column. But it is influenced by another column type.
I used this sql command:
"SELECT * FROM Table WHERE id = (SELECT MAX(id) FROM Table WHERE type = 1)"
ID column is bigint type, and type is nchar. I tried use it with type = '1' too, but same problem.
Error is after "id = " section
Thanks for reply
EDIT:
SqlCeCommand com = new SqlCeCommand();
if (LocalType == '1') { com = new SqlCeCommand("SELECT req_id FROM Requisition WHERE id = (SELECT MAX(id) FROM Requisition WHERE type = 1)", con); }
else if (LocalType == '2') { com = new SqlCeCommand("SELECT req_id FROM Requisition WHERE id = (SELECT MAX(b.id) FROM Requisition AS b WHERE b.type <> 1)", con); }
using (com)
{
SqlCeDataReader reader = com.ExecuteReader();
}
The easiest way to do this is using top. If this is your real code, then you need to "escape" the word "table" because it is a reserved word:
select top 1 t.*
from [table] t
where type = '1'
order by id desc
Try naming the tables:
SELECT *
FROM Table AS a
WHERE id = (SELECT MAX(b.id) FROM Table AS b WHERE b.type = 1)
After a while on google, find that SQLCE in version 3.5 support SELECT TOP expression, but with difference with formating. It must be write with brackets
SELECT TOP(1) * FROM MyTable

Query with parameters in C# (using SQL Server)

I have a problem with query in C#.
I have this part of code :
string query1 = #"
SELECT TOP #howManyRows * FROM
(
SELECT
PRODUCTCODE_.ID_ AS PRODUCTCODE_ID_,
PRODUCTCODE_.CATEGORY_ AS CATEGORY_,
PRODUCTCODE_.DESCRIPTION_ AS DESCRIPTION_,
PRODUCTCODE_.MANUFACTURER_ AS MANUFACTURER_,
PRODUCTLINE_.CREATION_DATE_ AS CREATION_DATE_,
ROW_NUMBER() OVER (ORDER BY PRODUCTCODE_.CATEGORY_) AS ROWNUMBER_,
TOTALROWS_ = COUNT(*) OVER()
FROM
PRODUCTCODE_
INNER JOIN
PRODUCTLINE_ ON PRODUCTLINE_.ID_ = PRODUCTCODE_.PRODUCTLINE_ID_
) _tmpList
WHERE
ROWNUMBER_ >= #startingWith
ORDER BY CATEGORY_
";
SqlParameter param1 = new SqlParameter();
param1.ParameterName = "#howManyRows";
param1.Value = resultPerPage; //`resultPerPage` is an integer function parameter
SqlParameter param2 = new SqlParameter();
param2.ParameterName = "#startingWith";
param2.Value = startsWith; //`startWith` is an integer function parameter
SqlCommand cmd = new SqlCommand( query1, connect );
cmd.Parameters.Add( param1 );
cmd.Parameters.Add( param2 );
When debug arrived to SqlDataReader reader = cmd.ExecuteReader(); then the exception is thrown:
Incorrect syntax near #howManyRows ...
Why ? I defined and added howManyRows with Parameters property.
Where is my mistakes ?
Change your top query syntax from
SELECT TOP #howManyRows * FROM
to
SELECT TOP (#howManyRows) * FROM
Try wrapping the parameter specified next to TOP in parentheses, like so:
SELECT TOP (#howManyRows) * FROM
You need parenthesis to parametrise TOP
SELECT TOP (#howManyRows) * FROM
This will work.
SELECT
PRODUCTCODE_.ID_ AS PRODUCTCODE_ID_,
PRODUCTCODE_.CATEGORY_ AS CATEGORY_,
PRODUCTCODE_.DESCRIPTION_ AS DESCRIPTION_,
PRODUCTCODE_.MANUFACTURER_ AS MANUFACTURER_,
PRODUCTLINE_.CREATION_DATE_ AS CREATION_DATE_,
ROW_NUMBER() OVER (ORDER BY PRODUCTCODE_.CATEGORY_) AS ROWNUMBER_,
TOTALROWS_ = COUNT(*) OVER()
FROM
PRODUCTCODE_
INNER JOIN
PRODUCTLINE_ ON PRODUCTLINE_.ID_ = PRODUCTCODE_.PRODUCTLINE_ID_
) _tmpList
WHERE
ROWNUMBER_ between #startingWith and (#startingWith + #howManyRows)
ORDER BY CATEGORY_
You need to add a couple of parenthesis to make it work.
SELECT TOP (#howManyRows) * FROM
Use SELECT TOP(#howManyRows) syntax
You can do
SELECT TOP (#howManyRows) * FROM
But this really depends on the Database Server you are using. For example, this is only supported from MSSQL Server 2005 upwards
If this does not work you can do the following...
You can include this into your query string. But this can result in Sql Injection if you don't check the value of your variable.
Sample
int top = 10;
Int32.TryParse(howManyRows.ToString(), out top);
string query1 = "SELECT TOP " + top.ToString() + #" * FROM
(
SELECT
PRODUCTCODE_.ID_ AS PRODUCTCODE_ID_,
PRODUCTCODE_.CATEGORY_ AS CATEGORY_,
PRODUCTCODE_.DESCRIPTION_ AS DESCRIPTION_,
PRODUCTCODE_.MANUFACTURER_ AS MANUFACTURER_,
PRODUCTLINE_.CREATION_DATE_ AS CREATION_DATE_,
ROW_NUMBER() OVER (ORDER BY PRODUCTCODE_.CATEGORY_) AS ROWNUMBER_,
TOTALROWS_ = COUNT(*) OVER()
FROM
PRODUCTCODE_
INNER JOIN
PRODUCTLINE_ ON PRODUCTLINE_.ID_ = PRODUCTCODE_.PRODUCTLINE_ID_
) _tmpList
WHERE
ROWNUMBER_ >= #startingWith
ORDER BY CATEGORY_
";

Categories