I think I've seen almost every page relating to this question, most likely answer was
Check if a SQL table exists
but didn't really understand it. This is what I got:
private void select_btn_Click(object sender, EventArgs e)
{
string theDate = dateTimePicker1.Value.ToString("dd-MM-yyyy");
SqlConnection SC = new SqlConnection("Data Source=ruudpc;Initial Catalog=leden;Integrated Security=True");
SqlCommand DateCheck = new SqlCommand("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '" + theDate + "'");
}
Now I want a return value from DateCheck.ExecuteScalar(); that can tell me if it exists or not, probably dead simple.
EDIT
Regardless for the sql injection part, and that for some this question is helpful, it is generally bad practice to create tables on the fly, I recommend you reconsider your ERD. Just saying.
Using IF EXISTS T-SQL
private void select_btn_Click(object sender, EventArgs e)
{
string theDate = dateTimePicker1.Value.ToString("dd-MM-yyyy");
// Enclose the connection inside a using statement to close and dispose
// when you don't need anymore the connection (to free local and server resources)
using(SqlConnection SC = new SqlConnection("Data Source=ruudpc;Initial Catalog=leden;Integrated Security=True"))
{
// Sql command with parameter
string cmdText = #"IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME=#name) SELECT 1 ELSE SELECT 0";
SC.Open();
SqlCommand DateCheck = new SqlCommand(cmdText, SC);
// Add the parameter value to the command parameters collection
DateCheck.Parameters.Add("#name", SqlDbType.NVarChar).Value = theDate
// IF EXISTS returns the SELECT 1 if the table exists or SELECT 0 if not
int x = Convert.ToInt32(DateCheck.ExecuteScalar());
if (x == 1)
MessageBox.Show("Table exists for date " + theDate);
else
MessageBox.Show("Table doesn't exist for date " + theDate);
}
}
The way you write the code can lead to sql injection attack.Parameterized SQL statements are an easy way to avoid SQL injection attacks and also a good codding practise
CREATE PROCEDURE checkTableExist
#theDate varchar(10)
AS
SET NOCOUNT ON;
IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=#theDate) SELECT 1 ELSE SELECT 0
C# code
try
{
string theDate = dateTimePicker1.Value.ToString("dd-MM-yyyy");
sqlConnection = new SqlConnection(dbConnectionString);
SqlCommand command = new SqlCommand("checkTableExist", sqlConnection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#theDate", SqlDbType.VarChar).Value = dateTimePicker1.Value.ToString("dd-MM-yyyy");
sqlConnection.Open();
int result = (Int32)command.ExecuteScalar();
sqlConnection.Close();
if (result == 1)
return true;//or any message
else
return false;
}
catch (SqlException ex)
{
Console.WriteLine("SQL Error" + ex.Message.ToString());
return false;
}
Related
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");
}
}
I am inserting a data row into my SQL Server database and then I want to query the data to get the unique identifier from the inserted row but my SqlDataReader is returning an empty dataset. I am thinking it maybe that the transaction hasn't been committed or something like that but I am not sure. I do not get an error.
Here is my code:
try
{
strQuery = "INSERT INTO clientnames VALUES(NEWID(),'" + txtACLastName.Text + "','" + txtACFirstName.Text + "'," + 1 + ")";
using (SqlCommand sqlInsertCmd = new SqlCommand(strQuery, sqlConn))
{
intQueryResult = sqlInsertCmd.ExecuteNonQuery();
if (intQueryResult == 0)
{
blnSuccess = false;
goto InsertClientNamesError;
}
else
{
blnSuccess = true;
}
sqlInsertCmd.Dispose();
}
if (blnSuccess)
{
strQuery = "select clientID from clientnames where firstname = '" + txtACFirstName.Text + "' and lastname = '" + txtACLastName.Text + "'";
using (SqlCommand sqlSelectCmd = new SqlCommand(strQuery, sqlConn))
{
SqlDataReader sqlDataRead = sqlSelectCmd.ExecuteReader();
while (sqlDataRead.Read())
{
strClientID = sqlDataRead.ToString();
}
sqlDataRead.Close();
sqlSelectCmd.Dispose();
}
}
}
catch (Exception exQuery)
{
System.Windows.MessageBox.Show("InsertClientNames: Error, " + exQuery.Message + ", has occurred.");
}
You are not getting the desired result because perhaps the SqlConnection is not opened explicitly (just a guess hard to tell without having full code). But this link shows you how to read from reader --> https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx
But I suggest that you Please do not do it this way. Reason is you are making Two round trips to the DB Server when only one would have done the job for you IF you were using stored procedures. Also you are exposing yourselves to SQL Injection attacks as you are not parameterizing your queries.
Stored procedure:
CREATE PROCEDURE dbo.INS_clientnames
(
#FirstName varchar(100),
#LastName varchar(100),
#NewID int out
)
AS
BEGIN
Declare #Err int
set #NewID = NewID() -- Get the New ID and store it in the variable ( #NewID ) that the SP will return back to the caller
INSERT INTO clientnames values (#NewID , #FirstName , #LastName)
SET #Err = ##ERROR
IF #Error <> 0 -- Check If there was an error
Begin
SET #NewID = -1 -- Indicates that there was an error. You could log this into a Log Table with further details like error id and name.
END
RETURN
END
C# code to execute the above stored procedure and get the NewID:
using(SqlConnection conn = new SqlConnection(connectionString ))
{
using(SqlCommand cmd = new SqlCommand("dbo.INS_clientnames", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters that the Stored Procedure expects
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar, 100);
cmd.Parameters.Add("#LastName" , SqlDbType.VarChar, 100);
cmd.Parameters.Add("#NewId" , SqlDbType.Int).Direction = ParameterDirection.Output;
// set parameter values that your code will send to the SP as parameter values
cmd.Parameters["#FirstName"].Value = txtACFirstName.Text ;
cmd.Parameters["#LastName"].Value = txtACLastName.Text ;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from #NewId
int NewID = Convert.ToInt32(cmd.Parameters["#NewId"].Value);
}
}
Add the following line to your stored procedure that inserts the record
SELECT SCOPE_IDENTITY()
This will return the last identity value inserted in that table.
And use cmd.ExecuteScalar() instead of ExecuteNonQuery()
ExecuteScalar() executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored. [More info][1]
I see two approaches to do this:
either you generate the new GUID on the client side in your C# code and pass it into the query - then you already know what the new id is going to be, so you don't need to do a second query to get it:
you create your GUID on the server side and return it to the caller using the OUTPUT clause in your query
Approach #1:
// define connection string and query
string connStr = "--your connection string here--";
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) VALUES(#ID, #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// create the GUID in C# - this is the ID - no need to go get it again - this *IS* the id
Guid id = Guid.NewGuid();
// set the parameters
cmd.Parameters.Add("#ID", SqlDbType.UniqueIdentifier).Value = id;
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Peter";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Miller";
// open connection, execute query, close connection
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
Approach #2:
// define connection string and query
string connStr = "--your connection string here--";
// query has an "OUTPUT" clause to return a newly inserted piece of data
// back to the caller, just as if a SELECT had been issued
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) OUTPUT Inserted.ClientID VALUES(NEWID(), #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// set the parameters - note: you do *NOT* send in a GUID value - the NEWID() will create one automatically, on the server
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Frank";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Brown";
// open connection
conn.Open();
// execute query and get back one row, one column - the value in the "OUTPUT" clause
object output = cmd.ExecuteScalar();
Guid newId;
if (Guid.TryParse(output.ToString(), out newId))
{
//
}
conn.Close();
}
i had the exact name in my database yet i still keep getting that error as titled.
An exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll but was not handled in user code
Image Link : http://i.imgur.com/tKtvlfj.png
Additional information: Invalid column name 'Username'.
protected void Button1_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ERegistrationConnectionString"].ConnectionString);
conn.Open();
string checkuser = "select count(*)from Employer where Username='" + TextBoxELUsername.Text + "'";
SqlCommand com = new SqlCommand(checkuser, conn);
int temp = Convert.ToInt32(com.ExecuteScalar().ToString());
conn.Close();
if (temp == 1)
{
conn.Open();
string checkPasswordQuery = "select password from Employer where Username='" + TextBoxELUsername.Text + "'";
SqlCommand passComm = new SqlCommand(checkPasswordQuery, conn);
string password = passComm.ExecuteScalar().ToString().Replace(" ","");
if (password == TextBoxLoginPassword.Text)
{
Session["New"] = TextBoxELUsername.Text;
Response.Write("Password is Correct");
}
else
{
Response.Write("Password Incorrect");
}
}
else
{
Response.Write("Username Incorrect");
}
}
Your SQL is invalid. You forgot a space between the count(*) and from keyword. Try this instead:
select count(*) from Employer where Username=
Also you should change your sql to not allow sql injections and use the Parameters object
In the case of your Sql statement to retrieve the count(*) you really should Parameterize that statement to prevent sql injection.
string checkuser = #"select count(*)from Employer where Username= ?";
SqlCommand com = new SqlCommand(checkuser, conn);
comm.Parameters.AddWithValue("?", TextBoxELUsername.Text );
In addition try returning the variable temp in this fashion.
int temp = (int)comm.ExecuteScalar();
Beyond that I would try creating a second connection contained within the IF statement. It may sound odd but that connection can be stripped out of memory before the IF statement is triggered and in turn the program has no idea what connection your are trying to open.
You could avoid a second connection all together by creating a single sql statement
string checkuser = #"select count(*)from Employer where Username= ? and password = ?";
SqlCommand com = new SqlCommand(checkuser, conn);
comm.Parameters.AddWithValue("?", TextBoxELUsername.Text );
comm.Parameters.AddWithValue("?", TextBoxLoginPassword.Text );
your count return will only exist is both the username and password are correct.
You may also want to use the following code to force case sensitivity on your query
alter database your_database collate Latin1_General_CS_AS
i want to store the data in sqlserver and i'm able with this code.Now i want to check if table is exists than insert the data or create new table and insert the data..So i need help...thnku
SqlConnection con = new SqlConnection("Data Source=PRAWAT; Initial Catalog=StudentData ;Integrated security=true; ");
string query = "insert into NewValidStudentData(StudentId,Name,Marks) values (#StudentId,#Name,#Marks);";
SqlCommand cmd = new SqlCommand();
SqlDataAdapter da = new SqlDataAdapter();
da.InsertCommand = new SqlCommand(query, con);
con.Open();
da.InsertCommand.Parameters.Clear();
da.InsertCommand.Parameters.AddWithValue("#StudentId", System.Data.SqlDbType.NVarChar).Value = value[0];
da.InsertCommand.Parameters.AddWithValue("#Name", System.Data.SqlDbType.NVarChar).Value = value[1];
da.InsertCommand.Parameters.AddWithValue("#Marks", System.Data.SqlDbType.NVarChar).Value = value[2];
da.InsertCommand.ExecuteNonQuery();
con.Close();
You can edit your query to something like:
IF (EXISTS
(SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'YourSchemaName'// if you don't know the name, try 'dbo'
AND TABLE_NAME = 'NewValidStudentData'))
BEGIN
INSERT INTO NewValidStudentData(StudentId, Name, Marks)
VALUES (#StudentId, #Name, #Marks);";
END
Just wrap this query as a string and execute the same. This way, you can control the table's existence and insert the data within a single call to database server.
First check if your table exists with this snippet (also see this answer):
bool exists;
string tableName = "WhatEverItIs";
try {
// ANSI SQL way. Works in PostgreSQL, MSSQL, MySQL.
var cmd = new OdbcCommand(
"select case when exists((select * from information_schema.tables where table_name = '" + tableName + "')) then 1 else 0 end");
exists = (int)cmd.ExecuteScalar() == 1;
} catch {
try {
// Other RDBMS. Graceful degradation
exists = true;
var cmdOthers = new OdbcCommand("select 1 from " + tableName + " where 1 = 0");
cmdOthers.ExecuteNonQuery();
} catch {
exists = false;
}
}
Then if it wasn't exist:
if(!exists) {
var createTableSql = "CREATE TABLE WHAT_YOUR_TABLE_SCHEME_IS";
// execute a command with above createTableSql, to create your table
}
And then, do the rest of your code
StudentId as NVARCHAR? Does Student Id has characters in it?
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[NewValidStudentData]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[NewValidStudentData](
StudentId NVARCHAR(10),
Name NVARCHAR(100),
Marks NVARCHAR(3)
)
END
Note: I would suggest handle this in stored procedure instead of writing all this in c# code.
I am trying to understand what is wrong with this select.
I want to get the last user_Id which was been added.
Here is the error message:
The parameterized query '(#Id_user int)SELECT SCOPE_IDENTITY() AS id_user' expects the parameter '#Id_user', which was not supplied.
Here is the SQL statement:
if (count >= 1) /* <=== verification from the insert SQL */
{
string selectStatement = "SELECT SCOPE_IDENTITY() AS id_user";
SqlCommand selectCommand = new SqlCommand(selectStatement, sqlConnection);
selectCommand.Parameters.Add("#Id_user", SqlDbType.Int, 0, "Id_user");
int newID = (int)selectCommand.ExecuteScalar();
int User_ID = Convert.ToInt32(selectCommand.Parameters["#Id_user"].Value);
Session["Id_user"] = User_ID;
buserIdAuthenticated = true;
Session["userIdAuthenticated"] = buserIdAuthenticated;
Response.Redirect("../pages/Welcome.aspx");
}
}
catch (SqlException ex)
{
lblMessage.Text = ex.Message;
}
finally
{
sqlConnection.Close();
}
you haven't defined an #parameter in your sql statement so you don;t need to add the parameter at all - just get the result of ExecuteScalar - you should be able to cast it to an int - although I cast it specifically in the sql statement too -
select cast(Scope_identity() as int) ....
so you'd end up with somthing like
string selectStatement = "SELECT cast(SCOPE_IDENTITY() AS int)";
SqlCommand selectCommand = new SqlCommand(selectStatement, sqlConnection);
object newIDobj = (int)selectCommand.ExecuteScalar();
if(newIDobj!=null)
Session["Id_user"] = (int)newIDobj;
Even better you could create a stored procedure and have the insert done there, where it can then return scope identity.
Edited to include example with insert. (just typed in here - so likely some typos)
int newID = -1;
string commandString = "insert (code, desc, numbervalue) values (#code, #desc,#numbervalue); select cast(scope_identity() as int);"
using(SqlCommand cmd = new SqlCommand(commandString))
{
try
{
cmd.Parameters.Add("#code", )
// etc
int newid=(int)(cmd.ExecuteScalar()??-1);
}
catch(Exception e)
{
// something went wrong
}
}
if(newID!=-1)
{
// do something;
}