Get summarized/sorted data from SQL Server in ASP.NET - sql

below is my sql table in which I'm saving student attendance
I'm trying to create a summarized attendance report as below:
Attendance Summary of all students:
Number of students present in class I: 1
Number of students present in class II: 1
Number of students present in class III: 0
But I don't exactly am finding a right way to do it. below is the sample code I'm trying to use to achieve this:
public void GetPresentCount()
{
using (SqlConnection con = new SqlConnection(constring))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("select count(*) as 'TotalPresent' from stud_att where att='Present' and a_date='"+ systemdate +"'", con))
{
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.Read())
{
totstuds.InnerText = dr["TotalCount"].ToString();
}
else
{
totstuds.InnerText = "0";
}
}
}
con.Close();
}
}
public void GetAbsentCount()
{
using (SqlConnection con = new SqlConnection(constring))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("select count(*) as 'TotalPresent' from stud_att where att='Present' and a_date='" + systemdate + "'", con))
{
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.Read())
{
totstuds.InnerText = dr["TotalCount"].ToString();
}
else
{
totstuds.InnerText = "0";
}
}
}
con.Close();
}
}
But I know this is not the right way.

I think you just want conditional aggregation:
select class,
sum(case when att = 'Present' then 1 else 0 end) as attendance
from stud_att
where a_date = ?
group by class
order by class;
The ? is a parameter placeholder to pass in the date. Don't munge SQL queries with constant values; pass them in as parameters.

Related

Updating user info but does not update and has no error

I'm trying to update multiple user info but it won't update. I have tried a lot of ways and all of them would execute, but they do not update the data, and yet throw no errors. Am I missing something?
Here is the code:
protected void Update_Click(object sender, EventArgs e)
{
using (SqlConnection sqlCon = new SqlConnection(connectionstring))
{
sqlCon.Open();
using (var sqlStt = sqlCon.CreateCommand())
{
sqlStt.CommandType = CommandType.Text;
sqlStt.CommandText = "UPDATE USERS SET LAST_NAME = #LAST_NAME, FIRST_NAME = #FIRST_NAME, BIRTHDATE = #BIRTHDATE, PHONE_NUM = #PHONE_NUM, EMAIL = #EMAIL WHERE USERNAME ='" + Session["USERNAME"] + "' ";
sqlStt.Parameters.AddWithValue("#LAST_NAME", Lname.Text);
sqlStt.Parameters.AddWithValue("#FIRST_NAME", Fname.Text);
sqlStt.Parameters.AddWithValue("#BIRTHDATE", Birthdate.Text);
sqlStt.Parameters.AddWithValue("#PHONE_NUM", Phone_num.Text);
sqlStt.Parameters.AddWithValue("#EMAIL", Email.Text);
sqlStt.ExecuteNonQuery();
}
sqlCon.Close();
Display_Info();
Disable_Field();
Notificationtext.Text = "Your account has been updated!";
}
}
void Disable_Field()
{
Lname.Enabled = false;
Fname.Enabled = false;
Birthdate.Enabled = false;
Phone_num.Enabled = false;
Email.Enabled = false;
}
void Display_Info()
{
using (SqlConnection sqlCon = new SqlConnection(connectionstring))
{
sqlCon.Open();
SqlCommand sqlCmd = new SqlCommand("SELECT LAST_NAME, FIRST_NAME, BIRTHDATE, PHONE_NUM, EMAIL FROM USERS WHERE USERNAME ='" + Session["USERNAME"] + "' ", sqlCon);
SqlDataReader reader;
reader = sqlCmd.ExecuteReader();
if (reader.Read())
{
Lname.Text = reader["LAST_NAME"].ToString();
Fname.Text = reader["FIRST_NAME"].ToString();
Birthdate.Text = reader["BIRTHDATE"].ToString();
Phone_num.Text = reader["PHONE_NUM"].ToString();
Email.Text = reader["EMAIL"].ToString();
}
sqlCon.Close();
}
}
I also wanted to display the update to the textbox then disable it. After I click update, the data before it was updated would display instead.

.NET Query with list as sql parameter

public SqlDataReader GetDataReader(List<SqlParameter> parameterValues){
System.Data.SqlClient.SqlConnection cn = new System.Data.SqlClient.SqlConnection();
cn.ConnectionString = SQLConnectionObj.ConnectionString;
cn.Open();
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
cmd.Parameters.AddRange(parameterValues.ToArray());
cmd.Connection = cn;
cmd.CommandText = SelectStatement;
cmd.CommandType = CommandType.Text;
return sReader = cmd.ExecuteReader();
}
When I try to add this for IN condition variable in select query,it fails.
Need to use this only for Fortify fix.Tried with dictionary Sql parameter.It works but increases the issue count up.
Please help me with this.And also if there is anything new which you want to add feel free to add those too.
But the following code works:-
public SqlDataReader GetDataReader(Dictionary<string, string> qParams)
{
SqlCommand SQLCommandObj = new SqlCommand(SelectStatement,
SQLConnectionObj);
string query=SelectStatement;
if (qParams.Count > 0)
{
foreach (string key in qParams.Keys)
{
string value = qParams[key];
SqlParameter par = new SqlParameter();
par.ParameterName = key;
par.Value = value;
SQLCommandObj.Parameters.Add(par);
}
}
foreach(SqlParameter par in SQLCommandObj.Parameters)
{
string key = par.ParameterName;
string value = par.Value as string;
query=query.Replace(key, value);
}
if (qParams.Count > 0)
{
SQLCommandObj.CommandText = "";
SQLCommandObj.CommandText = query;
}
SQLCommandObj.CommandTimeout = CustomCommandTimeout;
return SQLCommandObj.ExecuteReader(CommandBehavior.CloseConnection);
}

How to populate a collection property from SqlDataReader?

I have this simple SQL query:
SELECT CustomerName, OrderId
FROM Customer c
LEFT JOIN Orders o ON o.CustomerId = c.CustomerId
I need to populate my Customer entity from the query result:
public class Customer
{
public string Name { get; set; }
public IEnumerable<int> OrderIds { get; set; }
}
I'm reading data with SqlDataReader:
using(SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Customer c = new Customer();
c.Name = rdr["CustomerName"].ToString();
yield return c;
}
}
Question: What is the simplest and cleanest way to fill in the OrderIds property without using an ORM? The left join causes the query to return multiple rows per customer (because each customer has multiple orders) so now reading it row by row like the above code won't work? Is there any way to fill that entity and still use yield return for deferred execution?
1st version:
var customersRDR = from rCustomers in rdr.Cast<DbDataRecord>()
group rCustomers by rCustomers["CustomerName"] into custGroups
select new Customer
{
Name = (string)custGroups.Key,
OrderIds = from c in custGroups select (Int32)c["OrderId"]
};
2nd version:
DataTable dt = new DataTable();
dt.Load(rdr);
var customers = from c in dt.AsEnumerable()
group c by c["CustomerName"] into custGroups
select new Customer{
Name = custGroups.Key.ToString(),
OrderIds = from c in custGroups select Convert.ToInt32(c["OrderId"])
};
3rd version:
DataTable dt = new DataTable();
dt.Load(rdr);
var customerGroups = dt.AsEnumerable()
.GroupBy(c => c["CustomerName"]);
foreach (var customer in customerGroups){
Customer cust = new Customer();
cust.Name = customerGroup.Key.ToString();
cust.OrderIds = from c in customerGroup select Convert.ToInt32(c["OrderId"]);
}
List<int> orderIds = (from IDataRecord r in rdr
where (string) r["CustomerName"] == c.Name
select (int)r["OrderIds"]).ToList();
EDIT
This a bit tricky to do without an ORM. However another option is to use multiple readers. It would require you to have two queries - one for customer and one for orders. As an example:
private void GetCustomerWithOrders()
{
using (var conn = new SqlConnection("your connection string"))
{
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT CustomerName, CustomerId FROM Customer";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var customerId = reader.GetInt32(1); // CustomerId
List<int> orders = GetOrders(customerId);
}
}
}
}
}
private List<int> GetOrders(int customerId)
{
var orders = new List<int>();
using (var conn = new SqlConnection("your connectionstring"))
{
using (var cmd = new SqlCommand("SELECT OrderId FROM Orders WHERE CustomerId = #CustomerId", conn))
{
var param = new SqlParameter
{
ParameterName = "#CustomerId",
Value = customerId
};
cmd.Parameters.Add(param);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var orderId = reader.GetInt32(0); // OrderId
orders.Add(orderId);
}
}
}
}
return orders;
}
var dataReader = cmd.ExecuteReader();
var dataTable = new DataTable();
dataTable.Load(dataReader);

Run Sql select statement in a for / foreach loop

Hello I'm building a helping app for my students at the school using database and signalr to live update the list.
connection.Open();
using (var command = new SqlCommand(#"SELECT [Id], [Name] FROM [dbo].[HelpLists]", connection))
{
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
messages.Add(item: new Messages { Number = (int)reader["Id"], Message = (string)reader["Name"] });
}
}
The part of the code I want to chance is the While loop
Lets say my select statements get 3 rows. Then I would like to pass the command through a for / foreach loop Kinda like:
for (int i = 0; i < reader.FieldCount; i++)
{
messages.Add(item: new Messages { Number = i + 1, Message = (string)reader["Name"] });
}
Reason is i need the number to start at 1 and increase by 1 for each row in the select statement
You can try this code.
connection.Open();
using (var command = new SqlCommand(#"SELECT [Id], [Name] FROM [dbo].[HelpLists]", connection))
{
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
//my change is here
List<reader > readers = new List<reader>();
for(reader rs:readers )
{
System.out.println(rs.id);
System.out.println(rs.name);
}
}

Oracle columns update not happpening

I am trying to update a few columns in a Oracle table from my C# code.
Here is my method:
private static bool UpdateOracleTable(OracleTable table, string whereClause, List<int> entIDs)
{
try
{
var tableName = table.ToString();
using (OracleConnection conn = new OracleConnection(_oracleConnection))
{
conn.Open();
foreach (var id in entIDs)
{
whereClause = String.Format(whereClause, id);
var query = Resources.UpdateOracle;
query = String.Format(query, tableName, "20", DateTime.Now.ToString("yyyy/MM/dd"), whereClause);
using (OracleCommand cmd = new OracleCommand(query, conn))
{
cmd.ExecuteNonQuery();
}
}
}
return true;
}
catch (Exception ex)
{
Log.Debug(LogType.Error, ex);
return false;
}
}
Here is the Query:
UPDATE
{0}
SET
SYNC_STATUS = '{1}'
,SYNC_DATE = TO_DATE('{2}', 'yyyy/mm/dd')
{3}
And the where clause will look something like:
WHERE ID = {0}
This method updates about 10 records, and the rest stays null. This mehod does return true, and I have debugged, no exception is thrown.
Why does it not update all records?
This isn't an answer but might help debug the problem.
Instead of the like:
cmd.ExecuteNonQuery();
put in this:
int count = cmd.ExecuteNonQuery();
if (count == 0)
{
Console.WriteLine("");
}
Put a break on the Console.WriteLine("") and run it. The debugger will stop if no rows were updated. You can then check the query, and whether or not that ID actually exists.
The problem was with the WHERE clause. Since it contains a place holder {0}, after I I formatted the WHERE clause, the ID always stayed to the value it was formatted with first.
This is what my new method looks like.
private static bool UpdateOracleTable(OracleTable table, string whereClause, List<int> entIDs)
{
try
{
var tableName = table.ToString();
using (OracleConnection conn = new OracleConnection(_oracleConnection))
{
conn.Open();
foreach (var id in entIDs)
{
string originalWhere = whereClause;
originalWhere = String.Format(originalWhere, id);
var query = Resources.UpdateOracle;
query = String.Format(query, tableName, "20", DateTime.Now.ToString("yyyy/MM/dd"), originalWhere);
using (OracleCommand cmd = new OracleCommand(query, conn))
{
bool success = cmd.ExecuteNonQuery() > 0;
}
}
}
return true;
}
catch (Exception ex)
{
Log.Debug(LogType.Error, ex);
return false;
}
}
As can be seen, I added a variable 'originalWhere', that gets formatted, but most importantly, is being set to original WHERE clause parameter passed, so that it will always contain the place holder.