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");
}
}
Related
In Excel writing a VSTO Plugin (using C#) I'm trying to retrieve a value from a SQL database using OLEDB. When I debug this function, it fails on the catch.
The message I get is:
must declare the scalar variable \"#uname\"
But I already did this when I bound the parameter. What am I doing wrong?
public static int getUserID(string username)
{
int result = 0;
string sql = #"select top 1 [ID] FROM " + tbl_users + " WHERE ( [UNAME]=#uname );";
Console.WriteLine("sql: " + sql);
using (OleDbConnection conn = new OleDbConnection(connStr))
{
try
{
conn.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("#uname", username);
result = (int)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
result = -15;
}
finally
{
conn.Close();
conn.Dispose();
}
}
return result;
}
So I think I figured it out... This change works, but I don't really like it.
First I need to use OleDb parameter binding and not SqlParameter binding.
It also seems like OleDb does not like custom naming parameters like #uname and instead relies on the order of parameters (I don't like this).
So here's the fix in case anyone was interested:
public static int getUserID(string username)
{
int result = 0;
string sql = #"select top 1 [ID] FROM " + tbl_users + " WHERE ( [UNAME]=? );";
Console.WriteLine("sql: " + sql);
using (OleDbConnection conn = new OleDbConnection(connStr))
{
try
{
conn.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
cmd.CommandText = sql;
cmd.Parameters.Add("?", OleDbType.VarChar).Value = Convert.ToString(username);
result = (int)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
result = -15;
}
finally
{
conn.Close();
conn.Dispose();
}
}
return result;
}
When I am reading data from a sql db and want to add all the items into a list (ie. eonumlist) below. Do I need to specifically assign each field or can I mass assign this data? I'm doing this for a report and want to get the data quickly. Maybe I should use a dataset instead. I have 40+ fields to bring into the report and want to do this quickly. Looking for suggestions.
public static List<EngOrd> GetDistinctEONum()
{
List<EngOrd> eonumlist = new List<EngOrd>();
SqlConnection cnn = SqlDB.GetConnection();
string strsql = "select distinct eonum " +
"from engord " +
"union " +
"select 'zALL' as eonum " +
"order by eonum desc";
SqlCommand cmd = new SqlCommand(strsql, cnn);
try
{
cnn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
EngOrd engord = new EngOrd();
engord.EONum = reader["eonum"].ToString();
engord.Name = reader["name"].ToString();
engord.Address = reader["address"].ToString();
eonumlist.Add(engord);
}
reader.Close();
}
catch (SqlException ex)
{
throw ex;
}
finally
{
cnn.Close();
}
return eonumlist;
}
I do something similar storing data from a db into a combo box.
To do this i use the following code.
public static void FillDropDownList(System.Windows.Forms.ComboBox cboMethodName, String myDSN, String myServer)
{
SqlDataReader myReader;
String ConnectionString = "Server="+myServer+"\\sql2008r2;Database="+myDSN+";Trusted_Connection=True;";
using (SqlConnection cn = new SqlConnection(ConnectionString))
{
cn.Open();
try
{
SqlCommand cmd = new SqlCommand("select * from tablename", cn);
using (myReader = cmd.ExecuteReader())
{
while (myReader.Read())
{
cboMethodName.Items.Add(myReader.GetValue(0).ToString());
}
}
}
catch (SqlException e)
{
MessageBox.Show(e.ToString());
return;
}
}
}
This connects to the database and reads each record of the table adding the value in column 0 (Name) to a combo box.
I would think you can do something similar with a list making sure the index values are correct.
Store the data as xml, then deserialize the xml to the list.
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
I have this code that counts the number of records with the same year and date. But when I run the application it doesn't work. Here is my code:
try
{
string query = "SELECT * FROM tblOrder WHERE dateTime_coded=#dateTimeNow";
MySqlCommand cmd = new MySqlCommand(query, con);
cmd.Parameters.AddWithValue("#dateTimeNow", Convert.ToDateTime(DateTime.Now).ToString("yyyy-MM"));
MySqlDataReader dr = cmd.ExecuteReader();
MessageBox.Show("OK");
con.Open();
while (dr.Read())
{
count++;
}
dr.Close();
con.Close();
}
catch (Exception)
{
}
First you have an empty catch block which makes no sense
Atleast this would have been better
catch (Exception ex)
{
MessageBox(ex.Message);// you would know if in case it failed
}
Now the problem seems to be
MySqlDataReader dr = cmd.ExecuteReader();
MessageBox.Show("OK");
con.Open(); <--- opening after executing the reader !
you should try putting the connection in a using block
using(MySqlConnection con = new MySqlConnection())
{
//your stuff in here
}
Another observation
cmd.Parameters.AddWithValue("#dateTimeNow", Convert.ToDateTime(DateTime.Now).ToString("yyyy-MM"))
DateTime.Now is DateTime no need to Convert it again
A better approach to your problem is through ExecuteScalar (link for SqlServer but it is the same for MySql) and using the COUNT function
using(MySqlConnection con = new MySqlConnection("your_connection_string_here"))
{
con.Open();
string query = "SELECT COUNT(*) FROM tblOrder WHERE dateTime_coded=#dateTimeNow";
using(MySqlCommand cmd = new MySqlCommand(query, con))
{
cmd.Parameters.AddWithValue("#dateTimeNow", DateTime.Now.ToString("yyyy-MM");
int count = (int)cmd.ExecuteScalar();
Console.WriteLine("There are " + count.ToString() + " records");
}
}
As you can see, I have removed the try/catch block that is useless here because you don't do anything with the exception. This will stop the program if your query contains a syntax error or you can't establish a connection with the server. So, if a try/catch is really needed depends on your requirements
(Added also the observation on the DateTime.Now from V4Vendetta)
You can SELECT COUNT(*) FROM ... and then use cmd.ExecuteScalar() to retrieve the count returned.
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;
}