IDataReader Issue in .Net 1.1 and .Net 4.0 for Sybase DB - .net-4.0

I have a sybase DB which fetches results of a query properly as below...
select
S.ipoInternalID,
clientAccount,
clientPrice,
clientAccountType,
interestOnLoan =
CASE WHEN useHIBOR = 1 then
ROUND(financingAmount * (fixedRate + spreadRate) *
I.noOfDaysForInterest/365/100,2)
ELSE
ROUND(financingAmount * (I.fundingRate+ spreadRate) *
I.noOfDaysForInterest/365/100,2) END,
useHIBORSTR =
CASE WHEN useHIBOR = 1 then
"LOCK-IN RATE + SPREAD"
ELSE
"COST OF FUNDING + SPREAD" END,
from subscription S, iPO I, allocation A
where
S.ipoInternalID = #ipoInternalID and
I.ipoInternalID = #ipoInternalID and
A.ipoInternalID = #ipoInternalID and
S.ccassID *= A.ccassID
order by S.ccassID
Notice the way interestOnLoan field is calculated above.
Now when I run this query in SQL Advantage tool, it runs fine and gives me calculated values for interestOnLoan. When I run this query using .Net 1.1 API that loads this query via OleDB it runs fine...
myCommand.CommandText = myQuery;
myAdapter.SelectCommand = myCommand;
int i = myAdapter.Fill(resultSet);
My resultset fills ok.
But when I execute the above code in .net 4.0, the resultset errors out as
"Value was either too large or too small for a Decimal."
The value it has issues with is the interestOnLoan because I also executed the command via IDataReader as below...
using (var dr = myCommand.ExecuteReader())
{
resultSet.Tables.Add(ConvertDataReaderToTableManually(dr));
}
private static DataTable ConvertDataReaderToTableManually(IDataReader dr) {
var dt = new DataTable();
var dtSchema = dr.GetSchemaTable();
var listCols = new List<DataColumn>();
if (dtSchema != null) {
foreach (DataRow drow in dtSchema.Rows) {
var columnName = Convert.ToString(drow["ColumnName"]);
var t = (Type) (drow["DataType"]);
var column = new DataColumn(columnName, t);
column.Unique = (bool) drow["IsUnique"];
column.AllowDBNull = (bool) drow["AllowDBNull"];
column.AutoIncrement = (bool) drow["IsAutoIncrement"];
listCols.Add(column);
dt.Columns.Add(column);
}
}
// Read rows from DataReader and populate the DataTable
int j = 0;
while (dr.Read()) {
j++;
var dataRow = dt.NewRow();
for (int i = 0; i < listCols.Count; i++) {
try {
dataRow[((DataColumn)listCols[i])] = dr[i];
} catch (Exception ex1) { }
}
dt.Rows.Add(dataRow);
}
return dt;
}
Here it errors out at the dataRow[((DataColumn)listCols[i])] = dr[i] where it has issues reading from dr[i];
When observed the ith column is nothing but interestOnLoan.
So somehow .Net 4.0 is not able to read this value. It can read other decimal values correctly such as clientPrice.
Why could this be happening....
Also I wanted to ask is there any way I can load the values in the DataReader as Double (instead of Decimal) by default?

I didnt get the reason why .NET 4.0 had issues ith the above query but when I changed the query as below it worked in both (.Net 1.1 and 4.0)
select
S.ipoInternalID,
clientAccount,
clientPrice,
clientAccountType,
interestOnLoan = ROUND(
(CASE WHEN useHIBOR = 1 THEN
((financingAmount*(fixedRate + spreadRate) * .noOfDaysForInterest)/365.0)
ELSE
((financingAmount*(I.fundingRate+spreadRate)*I.noOfDaysForInterest)/365.0)
END) / 100.0, 2),
useHIBORSTR =
CASE WHEN useHIBOR = 1 then
"LOCK-IN RATE + SPREAD"
ELSE
"COST OF FUNDING + SPREAD" END,
from subscription S, iPO I , allocation A
where
S.ipoInternalID = #ipoInternalID and
I.ipoInternalID = #ipoInternalID and
A.ipoInternalID = #ipoInternalID and
S.ccassID *= A.ccassID
order by S.ccassID

Related

How to convert values of a datatable from string to integer

I'm making a fine calculator in a library system. In it,I need to calculate the fine of a given day. For this,I use a data table to load the fine amounts and then,I need to calculate the total fine amount by adding each fine amount.But I'm having a problem in parsing the fine values which are in string format to integer.Here is a screenshot of the error.
Here is a screenshot of the error.
And here is the code which I used to convert the string values to integer and calculate the total fine.
int sum1 = 0;
int myNum;
String Display;
private void btnNext_Click(object sender, EventArgs e)
{
try
{
if (rbtnToday.Checked == true)
{
DateTime today = DateTime.Today;
Con.Open();
String select_today_query = "SELECT Fine FROM BookReceiveMem WHERE RecDate='" + today + "'";
Sqlda = new SqlDataAdapter(select_today_query, Con);
DataTable Dt = new DataTable();
Sqlda.Fill(Dt);
Con.Close();
foreach (DataRow row in Dt.Rows)
{
myNum = int.Parse(Dt.Columns[0].ToString());
sum1 = sum1 + myNum;
}
Display = sum1.ToString();
MessageBox.Show("Today Fine Amount is= " + Display, "Today Fine Calculation", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
Is there any method to solve this problem?
Databases are really good at calculating things like a sum. If Fine is an integer in your database you can get it to sum all the rows and just return that:
SELECT SUM(Fine) As TotalFine
FROM BookReceiveMem
WHERE RecDate = #recDate
Which you could call from code without ever needing a DataTable as follows:
using(var cmd = Con.CreatCommand())
{
cmd.CommandText = "SELECT SUM(Fine) As TotalFine FROM BookReceiveMem WHERE RecDate = #recDate";
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("#recDate",DateTime.Today);
var result = (int)cmd.ExecuteScalar();
MessageBox.Show("Today Fine Amount is= " + result, "Today Fine Calculation", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
Note that the above uses a Parameterized Query which is much safer than using string concatenation
However, a more direct answer to your question:
myNum = int.Parse(Dt.Columns[0].ToString());
Here you're getting the Column and trying to turn that to an integer. What you actually meant to do was get the row value (and you dont need to Parse it - it's already an integer!)
myNum = (int)row["Fine"];

Entity Framework cast selected fields to varchar and concat them

I want do below query in Entity Framework
select
cast(p_min as varchar) + '' + cast(p_max as varchar)
from
user_behave_fact
where
beef_dairy_stat = 'True' and param_id = 2
group by
p_min,p_max
go
Since you have not mentioned a language, I am writing code in C#.
Try this:
using (var dbContext = new DatabaseContext())
{
var output = (
from fact in dbContext.user_behave_facts
where fact.beef_dairy_stat == "True" && fact.param_id == 2
group fact by new {fact.p_min, fact.p_max} in grp
select new
{
ColName = grp.Key.p_min.ToString() + " " + grp.Key.p_max.ToString()
}
).ToList();
}
.ToList() can be changed according to your expectations

MS SQL Query in C# - poor performance

I calculate outstanding customers balance in C# Winforms. The code below works, but it's slow. Is there any way to improve its performance?
public DataTable GetOutStandingCustomers()
{
decimal Tot = 0;
DataTable table = new DataTable();
SqlConnection con = null;
try
{
table.Columns.Add("Code", typeof(Int32));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("City", typeof(string));
table.Columns.Add("Tot", typeof(decimal));
string constr = ConfigHelper.GetConnectionString();
string query = "SELECT Code, Name,City FROM Chart WHERE LEFT(CODE,3)='401' AND Code > 401001 ";
string query0 = " SELECT(SELECT ISNULL( SUM(SalSum.Grand),'0' ) FROM SalSum WHERE SalSum.Code = #Code ) +( SELECT ISNULL(SUM(Journals.Amount),'0' ) FROM Journals WHERE Journals.DrCode = #Code ) -( SELECT ISNULL(SUM(RSalSum.Grand),'0' ) FROM RSalSum WHERE RSalSum.Code = #Code ) -( SELECT ISNULL(SUM(Journals.Amount),'0' ) FROM Journals WHERE Journals.CrCode = #Code )+(SELECT ISNULL(SUM(Chart.Debit),'0' ) FROM Chart WHERE Chart.Code = #Code) - (SELECT ISNULL(SUM(Chart.Credit), '0') FROM Chart WHERE Chart.Code = #Code)";
Person per = new Person();
con = new SqlConnection(constr);
SqlCommand com = new SqlCommand(query, con);
SqlCommand com0 = new SqlCommand(query0, con);
con.Open();
SqlDataReader r = com.ExecuteReader();
if (r.HasRows)
{
while (r.Read())
{
per.Name = Convert.ToString(r["Name"]);
per.City = Convert.ToString(r["City"]);
per.Code = Convert.ToString(r["Code"]);
com0.Parameters.Clear();
com0.Parameters.Add("#Code", SqlDbType.Int).Value = per.Code;
Tot = Convert.ToDecimal(com0.ExecuteScalar());
if (Tot != 0)
{
table.Rows.Add(per.Code, per.Name, per.City, Tot);
}
}
}
r.Close();
con.Close();
return table;
}
catch (Exception)
{
throw new Exception();
}
}
The performance problem is due to you retrieve all data from the server and filter data in the client using the complex computed expression that sum from seven tables:
if (Tot != 0)
{
table.Rows.Add(per.Code, per.Name, per.City, Tot);
}
This represent overhead over network plus you manually add the result to the datatable row by row.
The provided solution do filter in the server based on the computed expression using the CROSS APPLY
and auto create the datatable directly from the DataReader.
The benefit of CROSS APPLY is all columns are feasible to the main sql query, so you can filter on ToT column, filtering is done in the server (not the client).
public void SelctChart()
{
string sql2 = #"
select c.Code, c.Name,c.City ,oo.T
from chart c
cross apply
( select c.code,
(
(select ISNULL( SUM(SalSum.Grand),0 ) FROM SalSum WHERE SalSum.Code = c.code )
+( select ISNULL(SUM(j.Amount),0 ) FROM [dbo].[Jornals] j WHERE j.DrCode = c.code)
-( SELECT ISNULL(SUM(RSalSum.Grand),'0' ) FROM RSalSum WHERE RSalSum.Code = c.Code )
-( SELECT ISNULL(SUM(j.Amount),0 ) FROM [dbo].[Jornals] j WHERE j.CrCode = c.code )
+(SELECT ISNULL(SUM( c0.Debit),0 ) FROM [dbo].Chart c0 WHERE c0.Code = c.code)
- (SELECT ISNULL(SUM(c1.Credit), 0) FROM [dbo].Chart c1 WHERE c1.Code = c.code)
)T
) oo
where
oo.T >0
and LEFT(c.CODE,3)='401' AND c.Code > 401001
";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(sql2, connection);
//in case you pass #code as a a parameter
//command.Parameters.Add("#code", SqlDbType.Int);
//command.Parameters["#code"].Value = code;
try
{
connection.Open();
var reader = command.ExecuteReader();
while (!reader.IsClosed)
{
DataTable dt = new DataTable();
// Autoload datatable
dt.Load(reader);
Console.WriteLine(dt.Rows.Count);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
You can modify the method and pass code as a parameter
In this case it seems you're looping through and performing multiple queries using multiple Codes, you're also querying Chart twice. In this case you'd want to use a LEFT JOIN from Chart to your other tables.
ON Chart.Code = Salsum.Code
ON Chart.Code = Journal.Code
for example.
You will have to look at GROUP BY as well because you're aggregating some table columns by using SUM.
You may also need to make sure that Code is indexed on the tables you're querying. As long as Code is often queried like this and comparatively rarely Updated or Inserted to, then indexing the Code column on these tables is probably appropriate.
Left Joins : https://technet.microsoft.com/en-us/library/ms187518(v=sql.105).aspx
Indexing: https://technet.microsoft.com/en-us/library/jj835095(v=sql.110).aspx
Sorry I wrote a book on you here, but optimization often leads to a long answer (especially with SQL).
tldr;
Use a LEFT JOIN, grouping by Code
Index the Code columns

sql dependency query in c# throwing invalid sql, but works in sql server management studio [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
SQL query to check for dependency is throwing invalid when it runs and give results in sql server management studio. Can someone help to find out what is wrong in it.
i need to have SUM to display end results
public void GetAllTicket()
{
List<DashboardModel> resultlist = new List<DashboardModel>();
using (SqlConnection connection = new SqlConnection(_connString))
{
string query = "SELECT SUM(CASE WHEN [AssignedStaffID] = 8 and [IsAssignedStaffOverridden] = 0 THEN 1 ELSE 0 END) myticket,SUM(CASE WHEN [AgentGroupID] = 1 THEN 1 ELSE 0 END) agentgroup,SUM(CASE WHEN [AssignedStaffID] = 0 AND [AgentGroupID] = 1 THEN 1 ELSE 0 END) newticket,SUM(CASE WHEN [AssignedStaffID] = 8 AND [TicketStatusID] = 2 THEN 1 ELSE 0 END) resolvedticket FROM [dbo].[Ticket]";
using (SqlCommand command = new SqlCommand(query, connection))
{
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
connection.Open();
DataTable dt = new DataTable();
SqlDataReader reader = command.ExecuteReader();
dt.Load(reader);
if (dt.Rows.Count > 0)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
resultlist.Add(new DashboardModel
{
MyTicketCount = int.Parse(dt.Rows[i]["myticket"].ToString()),
AgentGroupTicketCount = int.Parse(dt.Rows[i]["agentgroup"].ToString()),
NewTicketCount = int.Parse(dt.Rows[i]["newticket"].ToString()),
ResolvedTicketCount = int.Parse(dt.Rows[i]["resolvedticket"].ToString())
});
}
}
}
}
NotifyAllClients(resultlist);
}
I get e.info= invalid below
public void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Info == SqlNotificationInfo.Invalid)
{
Console.WriteLine("The above notification query is not valid.");
}
if (e.Type == SqlNotificationType.Change)
{
GetAllTicket();
}
}
This is not a valid query for SqlDependency because you use aggregates (SUM), but have no group by clause. The microsoft documentation about SqlDependency is this page here:
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldependency%28v=vs.110%29.aspx
and it says
Query notifications are supported only for SELECT statements that meet a list of specific requirements.
There is a link to a very useful page which lists all these requirements in detail, and can be found here:
https://msdn.microsoft.com/library/ms181122.aspx
There is a section on "Supported SELECT Statements" which has this little gem:
The projected columns in the SELECT statement may not contain aggregate expressions unless the statement uses a GROUP BY expression.
It could be that there are other rules your query also breaks that are not immediately obvious from the code (eg, is dbo.tickets a view?).

Insert SQL statement is not working after checking against quantities from tables in database

I created a sale table which Insert function does not work properly. It shows the error message
Must declare the scalar variable "#iProductID"
at the statement
using (var sdRead = cmdOrder.ExecuteReader())
I am really stuck here. I also want to know how I can achieve for inserting SaleID with auto-increment without with any input field at the form. Every time I insert a new record, SaleID should be auto-generated and saved in the database.
My code below work like this. I checked available stocks from my Product table. If quantity order is greater than quantity from Product table, show error message.
Otherwise, proceed to inserting order information into Sale table. Any help is appreciated.
private void btnOrder_Click(object sender, EventArgs e)
{
int iQuantityDB;
int iCustomerID = Convert.ToInt32(txtCustomerID.Text);
int iProductID = Convert.ToInt32(txtProductID.Text);
decimal dPrice = Convert.ToDecimal(txtPrice.Text);
int iQuantity = Convert.ToInt32(txtQuantity.Text);
decimal dSubtotal = Convert.ToDecimal(txtSubTotal.Text);
decimal dGST = Convert.ToDecimal(txtGST.Text);
decimal dTotal = Convert.ToDecimal(txtTotal.Text);
string strConnectionString = #"Data Source = KK\SQLEXPRESS; Integrated Security = SSPI; Initial Catalog = JeanDB; MultipleActiveResultSets=True;";
using (var sqlconn = new SqlConnection(strConnectionString))
{
sqlconn.Open();
string querySelectQuantity = #"Select Quantity from dbo.JeanProduct WHERE ProductID = #iProductID";
using (var cmdOrder = new SqlCommand(querySelectQuantity, sqlconn))
{
using (var sdRead = cmdOrder.ExecuteReader())
{
sdRead.Read();
iQuantityDB = Convert.ToInt32(sdRead["Quantity"]);
}
}
if (iQuantityDB > iQuantity)
{
string InsertQuery = #"INSERT INTO Sale(CustomerID, ProductID, Price, Quantity, Subtotal, GST, Total)VALUES(#iCustomerID, #iProductID, #dPrice, #iQuantity, #dSubtotal, #dGST, #Total)";
using (var InsertCMD = new SqlCommand(InsertQuery, sqlconn))
{
InsertCMD.Connection = sqlconn;
InsertCMD.Parameters.AddWithValue("#iCustomerID", iCustomerID);
InsertCMD.Parameters.AddWithValue("#iProdcutID", iProductID);
InsertCMD.Parameters.AddWithValue("#dPrice", dPrice);
InsertCMD.Parameters.AddWithValue("#iQuantity", iQuantity);
InsertCMD.Parameters.AddWithValue("#dSubtotal", dSubtotal);
InsertCMD.Parameters.AddWithValue("#dGST", dGST);
InsertCMD.Parameters.AddWithValue("#dTotal", dTotal);
InsertCMD.ExecuteNonQuery();
LoadDataonTable();
}
}
else
{
MessageBox.Show("no more stock");
}
sqlconn.Close();
}
}
At the line using (var sdRead = cmdOrder.ExecuteReader()) your SQL SELECT query is using a parameter - WHERE ProductID = #iProductID - but this hasn't been set. Hence the error message Must declare the scalar variable "#iProductID"
Just add cmdOrder.Parameters.AddWithValue("#iProductID", iProductID) between defining the SQL and executing it, and that should clear that problem.
Moving on to the next one - you're using AddWithValue("#dTotal" but it's #Total in the SQL :)