Retrieving total count from database to c# - c#

This query is been executed in database.
select COUNT(*) from Patient_Data where DummyValue = 'Y';
104
I have to retrieve this number (104) from database to asp.net with c# so that when the count becomes zero I have to disable a button, How to retrieve this number from database into the code. It should be stored as integer.
I have tried these line of code in c#
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("select COUNT(*) as PatientCount from Patient_Data where DummyValue = 'Y' ", cn))
{
try
{
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
int Patcount;
if (rdr.Read())
{
//Code Required
}
}
}
catch (Exception ex)
{
// handle errors here
}
}
}

use alias to get the count as below:
select COUNT(*) as PatientCount from Patient_Data where DummyValue = 'Y';
Read the PatientCount value in code.
you can use GetInt32() function to get the count as int.
Note: you are passing the parameter values in your query which leads to Sql Injection Attacks, so you could use Parameterized Sql Queries to avoid them.
sample code is asbelow:
private int readPatientData()
{
int PatientCount = 0;
String strCommand = "select COUNT(*) as PatientCount from Patient_Data where DummyValue = #MyDummyValue";
using (SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString))
{
sqlConnection.Open();
using (SqlCommand sqlcommand=new SqlCommand(strCommand,sqlConnection))
{
sqlcommand.Parameters.Add(new SqlParameter("MyDummyValue", 'Y'));
SqlDataReader sqlReader = sqlcommand.ExecuteReader();
if (sqlReader.Read())
PatientCount = sqlReader.GetInt32(0);
}
}
return PatientCount;
}

I solved my issue with these lines of code.
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("select COUNT(*) as PatientCount from Patient_Data where DummyValue = 'Y' ", cn))
{
try
{
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
//int Patcount;
if (rdr.Read())
{
int Patcount = int.Parse(rdr["PatientCount"].ToString());
if (Patcount != 0)
{
Label3.Visible = true;
Label3.Text = "You have already have "+Patcount+" dummy records,Please update those records by clicking Update Dummy Records Link.";
btnSkipSubmit.Visible = false;
}
//Code Required
}
}
}
catch (Exception ex)
{
// handle errors here
}
}
}

Update based on code change in question
You can write rdr.GetInt32(3); instead of code required in your code.
previous answer
You need to use ExecuteScalar method while executing your command. Here is the example from msdn:
static public int AddProductCategory(string newName, string connString)
{
Int32 newProdID = 0;
string sql =
"INSERT INTO Production.ProductCategory (Name) VALUES (#Name); "
+ "SELECT CAST(scope_identity() AS int)";
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.Add("#Name", SqlDbType.VarChar);
cmd.Parameters["#name"].Value = newName;
try
{
conn.Open();
newProdID = (Int32)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
return (int)newProdID;
}
In this example they are returning newly added product Id.
ExecuteScalar returns object that you can check for null and cast to number as you know with int.parse method or the best one you know.

As Per my knowledge there are three ways to do this:
Using COUNT you can do this as below:
select COUNT(*) as RowCount from Patient_Data where DummyValue = 'Y';
Using ROW_NUMBER you can do this as below:
Select ROW_NUMBER() OVER (ORDER BY Patient_Data.ID DESC) AS RowNumber from Patient_Data where DummyValue = 'Y';
And there is another way but that way is only to get the row count and is the fastest way to get the row count in sql server according to me.
SELECT
Total_Rows= SUM(st.row_count)
FROM
sys.dm_db_partition_stats st
WHERE
object_name(object_id) = 'Patient_Data' AND (index_id < 2)
That's all

Related

Correct use of Try Catch for the SQL connection in C#

Is this code correct in means of Try/Catch? I need to value whether the action is done or not to inform the user about the result, so I will then get the bool value to know if connection was successful.
public static bool CreateSQLDatabaseTable()
{
var connString = "Server=localhost\\SQLEXPRESS;Integrated Security = SSPI; database = MyDB";
string cmdText = "SELECT count(*) as Exist from INFORMATION_SCHEMA.TABLES where table_name =#Product";
try
{
using (var sqlConnection = new SqlConnection(connString))
{
using (var sqlCmd = new SqlCommand(cmdText, sqlConnection))
{
sqlCmd.Parameters.Add("#Product", System.Data.SqlDbType.NVarChar).Value = "Product";
sqlConnection.Open();
sqlCmd.ExecuteScalar();
if ((int)sqlCmd.ExecuteScalar() != 1)
{
using (SqlCommand command = new SqlCommand("CREATE TABLE Product (Id INT, UserId TEXT, CreationDate TEXT, Name TEXT)", sqlConnection))
{
command.ExecuteNonQuery();
return true;
}
}
}
}
return false;
}
catch
{
return false;
}
}
Your method can actually have 3 outcomes:
The table was created successfully (method returns true)
The table already exists (method returns false)
There was an error trying to create the table (exception is thrown)
So you should handle the exception outside of this method and you should not blindly catch all Exceptions. You should only handle the SqlException so that other exceptions will not be handled. Also you should be logging the exception somewhere as a good practice.
For more information on the SqlException
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlexception(v=vs.110).aspx
public static bool CreateSQLDatabaseTable()
{
var connString = "Server=localhost\\SQLEXPRESS;Integrated Security = SSPI; database = MyDB";
string cmdText = "SELECT count(*) as Exist from INFORMATION_SCHEMA.TABLES where table_name =#Product";
using (var sqlConnection = new SqlConnection(connString))
{
using (var sqlCmd = new SqlCommand(cmdText, sqlConnection))
{
sqlCmd.Parameters.Add("#Product", System.Data.SqlDbType.NVarChar).Value = "Product";
sqlConnection.Open();
sqlCmd.ExecuteScalar();
if ((int)sqlCmd.ExecuteScalar() != 1)
{
using (SqlCommand command = new SqlCommand("CREATE TABLE Product (Id INT, UserId TEXT, CreationDate TEXT, Name TEXT)", sqlConnection))
{
command.ExecuteNonQuery();
return true;
}
}
}
}
return false;
}
public static void Main()
{
try
{
bool wasCreated = CreateSQLDatabaseTable();
}
catch (SqlException ex)
{
// Handle the SQL Exception as you wish
Console.WriteLine(ex.ToString());
}
}
I would solve such a problem through a single query that does the exists check itself and returns whether it was created or not.
public static bool CreateSQLDatabaseTable() {
var connString = "...";
const string tableName = "Product";
string cmdText = $"IF EXISTS (SELECT TOP(1) 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG = DB_NAME() AND TABLE_SCHEMA = 'dbo' AND TABLE_NAME = '{tableName}' AND TABLE_TYPE = 'BASE TABLE') BEGIN\r\n" +
$" SELECT CAST(0 AS BIT) AS CreatedNow\r\n" +
$"END ELSE BEGIN\r\n" +
$" CREATE TABLE dbo.{tableName}(Id INT, CreatorId INT, CreationDate DATETIME, CreationDateUtc DATETIME, Name NVARCHAR)\r\n" +
$" SELECT CAST(1 AS BIT) AS CreatedNow\r\n" +
$"END";
using (var sqlConnection = new SqlConnection(connString)) {
using (var sqlCmd = new SqlCommand(cmdText, sqlConnection)) {
sqlConnection.Open();
return (bool)sqlCmd.ExecuteScalar();
}
}
}

C# SQL Add parameter

I tried to return a row by executing following SQL query in C#:
SqlCommand cmd = new SqlCommand();
string selectquery = "SELECT TOP (1) [ZVNr] ZVNR_TABLE WHERE [ZVNr] = #zvnr order by [ZVNr] DESC";
cmd.Parameters.AddWithValue("#zvnr", "20170530-01");
cmd.CommandText = selectquery;
cmd.CommandType = CommandType.Text;
cmd.Connection = sqlConnection;
try
{
sqlConnection.Open();
int recordsAffected = cmd.ExecuteNonQuery();
if(recordsAffected != -1)
{
return 0;
}
else
{
return 1;
}
And the "ZVNR_TABLE" looks like this:
ZVNR | varchar (50)
20170530-01
The result is always --> recordsAffected = -1
Although when I'm executing the same SQL query in Microsoft SQL Server Management Studio, it works.
You're using a SELECT statement in your code with cmd.ExecuteNonQuery which is used for INSERT or UPDATE statements.
You have to use a SQLDataReader (more than 1 row and(!) column) or Scalar (1 row/1col = one "item").
MSDN Example for SQLDataReader:
//SELECT col1, col2, ..., coln FROM tbl;
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine("{0}\t{1}", reader.GetInt32(0),
reader.GetString(1));
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
MSDN Example for ExecuteScalar:
//SELECT COUNT(*) FROM region; or any other single value SELECT statement
int count = (int)cmd.ExecuteScalar(); //cast the type as needed
If you want the affected count after you change items in your database, you can get it by using cmd.ExecuteNonQuery which returns that count:
MSDN Example for ExecuteNonQuery:
//INSERT INTO tbl (...) VALUES (...) or any other non-query statement
int rowsAffected = (Int32)cmd.ExecuteNonQuery();
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command.
Because you are Selecting the data from the datatable not inserting or updating the records that's why recordsAffected is always -1
Answers given above are ok but if you want just to see if it exist you can do a count instead
using (SqlConnection connection = new SqlConnection(connectionstring))
{
string query = "SELECT Count([ZVNr]) ZVNR_TABLE WHERE [ZVNr] = #zvnr order by [ZVNr] DESC";
using (SqlCommand cmd = new SqlCommand(query, connection))
{
cmd.Parameters.AddWithValue("#zvnr", "20170530-01");
try
{
connection.Open();
int result = (int)cmd.ExecuteScalar();
}
}
}
ExecuteNonQuery() is used for INSERT or UPDATE statements and returns the number of rows affected.
If you want to return a single field of a row, you have to use ExecuteScalar()
using (SqlConnection connection = new SqlConnection(connectionstring))
{
string query = "SELECT TOP (1) [ZVNr] ZVNR_TABLE WHERE [ZVNr] = #zvnr order by [ZVNr] DESC";
using (SqlCommand cmd = new SqlCommand(query, connection))
{
cmd.Parameters.AddWithValue("#zvnr", "20170530-01");
connection.Open();
object result = cmd.ExecuteScalar();
}
}

Check if table exists using command

I'm trying to write a method to check if a table exists. I am trying to use the using statement to keep it consistent through my database.
public void checkTableExists()
{
connectionString = #"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\keith_000\Documents\ZuriRubberDressDB.mdf;Integrated Security=True;Connect Timeout=30";
string tblnm = "BasicHours";
string str = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = " + tblnm + ");";
SqlDataReader myReader = null;
int count = 0;
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(str, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
MessageBox.Show("The count is " + count);
myReader = command.ExecuteReader();
while (myReader.Read())
{
count++;
}
myReader.Close();
MessageBox.Show("Table Exists!");
MessageBox.Show("The count is " + count);
}
connection.Close();
}
}
}
catch (SqlException ex)
{
MessageBox.Show("Sql issue");
}
catch (Exception ex)
{
MessageBox.Show("Major issue");
}
if (count > 0)
{
MessageBox.Show("Table exists");
}
else
{
MessageBox.Show("Table doesn't exists");
}
}
It throws an exception when it hits the try block. It catches in the SqlException block.
This is the point where I am learning to interact with databases again. The solution would be good, but more importantly, a brief explanation of where I have need to learn how to improve my code.
Thanks
Keith
Your code fails because when you write directly a query searching for a string value then this value should be enclosed in single quotes like 'BasicHours'.
However there are some improvements to apply to your actual code.
First, you can use a simplified sql command.
Second, you use parameters instead of string concatenations.
SqlCommand cmd = new SqlCommand(#"IF EXISTS(
SELECT 1 FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #table)
SELECT 1 ELSE SELECT 0", connection);
cmd.Parameters.Add("#table", SqlDbType.NVarChar).Value = tblName;
int exists = (int)cmd.ExecuteScalar();
if(exists == 1)
// Table exists
This command text don't require you to use an SqlDataReader because the query returns just one row with one 'column' and the value of this single cell is either 1 or 0.
A lot less overhead.
A part from this, it is of uttermost importance, that you never build sql queries concatenating strings. This method is well know to cause problems.
The worse is called SQL Injection and could potentially destroy your database or reveal confidential information to hackers. The minor ones are crashes when the string concatenated contains single quotes. Use always a parameterized query.
I have used the following code in my project and worked for me:
try
{
using (con = new SqlConnection(Constr);)
{
con.Open();
string query = $"IF EXISTS (SELECT * FROM sys.tables WHERE name = '{tableName}') SELECT 1 ELSE Select 0;"
Exists = int.Parse(sqlQuery.ExecuteScalar().ToString())==1;
con.Close();
}
}
catch{}
The problem could be the line: string tblnm = "BasicHours";. You table name is a string and should be apostrophed, try this: string tblnm = "'BasicHours'";
Inside catch blocks you could also log exception messages and details.
Thanks for the help on this issue. This is the solution that I'm implemnenting.
public void checkTableExists()
{
connectionString = #"
Data Source=(LocalDB)\MSSQLLocalDB;
AttachDbFilename=C:\Users\keith_000\Documents\ZuriRubberDressDB.mdf;
Integrated Security=True;
Connect Timeout=30";
string tblName = #"BasicHours";
string str = #"IF EXISTS(
SELECT 1 FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #table)
SELECT 1 ELSE SELECT 0";
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(str, connection))
{
connection.Open();
SqlCommand cmd = new SqlCommand(str, connection);
cmd.Parameters.Add("#table", SqlDbType.NVarChar).Value = tblName;
int exists = (int)cmd.ExecuteScalar();
if (exists == 1)
{
MessageBox.Show("Table exists");
}
else
{
MessageBox.Show("Table doesn't exists");
}
connection.Close();
}
}
}
catch (SqlException ex)
{
MessageBox.Show("Sql issue");
}
catch (Exception ex)
{
MessageBox.Show("Major issue");
}
}

Is there a better way to get table structure?

Is there a better way to fetch using a different SQL query?
Have also added the code snippet (though not really related to my question).
select * from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA =
'$schema_name$', TABLE_NAME='$table_name$';
public TableStructure GetTableStructure(string TableName, MySqlConnection Connection)
{
if (Connection == null)
throw new ArgumentNullException("Sql Connection should be initialized.");
string sqlQuery = #"select * from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '$schema_name$', TABLE_NAME='$table_name$'";
sqlQuery = sqlQuery.Replace("$table_name$", TableName);
sqlQuery = sqlQuery.Replace("$schema_name$", SchemaName);
TableStructure tableStructure = null;
try
{
using (MySqlCommand sqlCmd = new MySqlCommand(sqlQuery, Connection))
{
if (Connection.State == ConnectionState.Closed)
Connection.Open();
using (MySqlDataReader dr = sqlCmd.ExecuteReader())
{
while (dr.Read())
{
...
...
//tableStructure = TableStructure.GetTableStructureFromDataReader(TableName, dr);
}
}
}
}
catch (Exception)
{
//TODO
throw new Exception("Error occured while obtaining tables list");
}
return tableStructure;
}
A WHERE statement with multiple conditions requires an AND / OR to join the two conditions
string sqlQuery = #"select * from INFORMATION_SCHEMA.COLUMNS
where TABLE_SCHEMA = '$schema_name$' AND TABLE_NAME='$table_name$'";
And instead of using a REPLACE to set your string values (a dangerous practice if the input are typed directly by your end user) you could use a parameterized query
string sqlQuery = #"select * from INFORMATION_SCHEMA.COLUMNS
where TABLE_SCHEMA = #schema AND TABLE_NAME=#table";
using (MySqlCommand sqlCmd = new MySqlCommand(sqlQuery, Connection))
{
sqlCmd.Parameters.AddWithValue("#schema", SchemaName);
sqlCmd.Parameters.AddWithValue("#table", TableName);
.....

How can I return a single value from an SqlDataReader?

I forget to return value in single tier application.
public int Studentid()
{
try
{
SqlConnection con = new SqlConnection(connectionStr);
SqlCommand cmd = new SqlCommand("SELECT s_id FROM student where name = + ('" + Request.QueryString.ToString() + "')", con);
con.Open();
SqlDataReader dr = null;
con.Open();
dr = cmd.ExecuteReader();
if (dr.Read())
{
//Want help hear how I return value
}
con.Close();
}
catch (Exception ex)
{
throw ex;
}
}
Here is a version of your method that achieves what you're after.
public int GetStudentId()
{
var sql = string.Format("SELECT s_id FROM student where name = '{0}'", Request.QueryString);
using (var con = new SqlConnection(connectionStr))
using (var cmd = new SqlCommand(sql, con))
{
con.Open();
var dr = cmd.ExecuteReader();
return dr.Read() ? return dr.GetInt32(0) : -1;
}
}
There's no need to use try/catch when you don't do anything with the exception except re-throw (and in fact you were losing the original stack trace by using throw ex; instead of just throw;. Also, the C# using statement takes care of cleaning up your resources for you in fewer lines of code.
IMPORTANT
Passing the query string directly into SQL like that means that anyone can execute random SQL into your database, potentially deleting everything (or worse). Read up on SQL Injection.
You should use using blocks, so that you are sure that the connection, command and reader are closed correctly. Then you can just return the value from inside the if statement, and doesn't have to store it in a variable until you have closed the objects.
You only have to open the connection once.
You should use parameterised queries, instead of concatenating values into the query.
public int Studentid() {
try {
using (SqlConnection con = new SqlConnection(connectionStr)) {
using (SqlCommand cmd = new SqlCommand("SELECT s_id FROM student where name = #Name", con)) {
cmd.Parameters.Add("#Name", DbType.VarChar, 50).Value = Request.QueryString.ToString();
con.Open();
using (SqlDataReader dr = cmd.ExecuteReader()) {
if (dr.Read()) {
return dr.GetInt32(0);
} else {
return -1; // some value to indicate a missing record
// or throw an exception
}
}
}
}
} catch (Exception ex) {
throw; // just as this, to rethrow with the stack trace intact
}
}
The easiest way to return a single value is to call ExecuteScalar. You should also fix your SQL injection bug. And did you mean to encode the entire query string array, or just to pick out a single value?
public int StudentId()
{
string sql = "SELECT s_id FROM student WHERE name = #name";
using (var con = new SqlConnection(connectionStr))
{
using (var cmd = new SqlCommand(sql, con))
{
cmd.Parameters.Add("#name", DbType.VarChar, 256).Value = Request.QueryString["name"];
con.Open();
return (int)cmd.ExecuteScalar();
}
}
}
try this:
int s_id = (int) dr["s_id"];
int studId=0;
if(rdr.Read())
{
studId=rdr.GetInt32(rdr.GetOrdinal("s_id"));
}
if (dr.Read())
{
//Want help hear how i return value
int value = dr.GetInt32("s_id");
}
Like this?
public int Studentid()
{
int studentId = -1;
SqlConnection con = null;
try
{
con = new SqlConnection(connectionStr);
SqlCommand cmd = new SqlCommand("SELECT s_id FROM student where name = + ('" + Request.QueryString.ToString() + "')", con);
SqlDataReader dr = null;
con.Open();
dr = cmd.ExecuteReader();
if (dr.Read())
{
studentId = dr.GetInt32(0);
}
dr.Close();
}
catch (Exception ex)
{
throw ex;
}
finally
{
if(con != null)
con.Close();
con = null;
}
return studentId;
}

Categories