Issues with Increment MS-SQL, C# - c#

I am having an issue with the increment for the ID. The ID would increase by one every time I click insert, but the problem occurs when the ID 2, it would insert the values twice, if ID 3, it would insert the values three times, and so on.
There are couple of options that I have been trying. One is Max and the other one is finding the last inserted value and add one to the ID just.
I would appreciate if anyone can help me out with this. Thanks
public partial class LoginInfo : System.Web.UI.Page
{
static string myConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
private void GenerateID()
{
SqlConnection myConnection = new SqlConnection(myConnectionString);
string myQuery1 = "Select Count(S_ID) from Student_Name";
SqlCommand cmd = new SqlCommand(myQuery1, myConnection);
myConnection.Open();
int addOneS_ID_Table1 = Convert.ToInt32(cmd.ExecuteScalar());
myConnection.Close();
addOneS_ID_Table1++;
lblstdID.Text = addOneS_ID_Table1.ToString();
myConnection.Open();
cmd.CommandText = "Select Count(P_ID) from Student_Pass";
int addOneP_ID_Table2 = Convert.ToInt32(cmd.ExecuteScalar());
myConnection.Close();
addOneP_ID_Table2++;
lblstdPass.Text = addOneP_ID_Table2.ToString();
/*-----------------------------------------------------------------*/
//SqlConnection myConnection = new SqlConnection(myConnectionString);
//SqlCommand cmd = new SqlCommand("SELECT MAX(S_ID) as max_S_ID from Student_Name",myConnection);
//cmd.CommandType = CommandType.Text;
//myConnection.Open();
//lblstdID.Text = Convert.ToString(cmd.ExecuteScalar());
//cmd.CommandText = "SELECT MAX(P_ID) as max_P_ID FROM Student_Pass";
//lblstdPass.Text = Convert.ToString(cmd.ExecuteScalar());
//myConnection.Close();
}
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
GenerateID();
}
}
protected void btnInsert_Click(object sender, EventArgs e)
{
SqlConnection myConnection = new SqlConnection(myConnectionString);
string myQuery = "Insert into Student_Name(S_ID,STUDENT_NAME) VALUES" + "(#S_ID,#STUDENT_NAME)";
SqlCommand cmd = new SqlCommand(myQuery,myConnection);
cmd.Parameters.Add("#S_ID", SqlDbType.Int).Value = lblstdID.Text;
cmd.Parameters.Add("#STUDENT_NAME", SqlDbType.VarChar).Value = txtstdName.Text;
if(myConnection.State == ConnectionState.Closed)
{
myConnection.Open();
}
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
//Second Table
cmd.CommandText = "Insert into Student_Pass(P_ID,PASSWORD) VALUES" + "(#P_ID,#PASSWORD)";
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("#P_ID", SqlDbType.Int).Value = lblstdPass.Text;
cmd.Parameters.Add("#PASSWORD", SqlDbType.VarChar).Value = txtStdPass.Text;
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
myConnection.Close();
GenerateID();
lblResult.Text = "Successfully Saved";
GridView1.DataBind();
}
}

Problem is with your query since you are getting COUNT(S_ID) which is going to get you count of records doesn't necessarily will give exact ID number. You should rather try MAX(S_ID) or ORDER BY clause saying
Select MAX(S_ID) from Student_Name
(OR)
Select TOP 1 S_ID from Student_Name ORDER BY S_ID DESC;
But recommended, You should actually go with SQL Server ##IDENTITY or SCOPE_IDENTITY() to get the last inserted record ID (assuming that S_ID is an IDENTITY column)

It's highly recommended to not use max or top in order to determine the "next" identifier to use, simply because of the cost associated with it.
However, there are some other pitfalls to using max and top especially if there is a chance that nolock is used (which is a whole other conversation). I've seen a lot of web applications use max and has proven to be a performance killer.
Rahul is right, ##identity or scope_identity are good alternatives. However, I think this calls for using a native SQL Server sequence, which was introduced in SQL Server 2012. It was something that application developers have been waiting for and Microsoft finally delivered.
The issue with using ##identity or scope_identity is that you actually have to write rows to some table before you can even contemplate doing something.
This makes it a bit more costly and messier than what it may need to be. In the case of using a sequence, you can issue a new sequence number and then decide what to do and once you decide what to do you're still guaranteed that you're the only one with that sequence number.
You would create a sequence like this. You should check out the documentation as well.
create sequence dbo.StudentIdSeq
as int -- this can be any integer type
start with 1 -- you can start with any valid number in the int, even negative
increment by 1;
go
Then you issue new sequence numbers by doing this ...
select next value for StudentIdSeq;
It may still be good to create a stored procedure with an output parameter that you can call from C# (which is what I would do). In fact you may want to take it a step further, in the case that you have a bunch of sequences, and create a slick stored procedure that will get a new sequence based on the type that is being requested from the caller.

Related

Comparing id from user to a table asp.net

As I am new to coding I have to get an id from user and compare it to a table from students that contains a foreign key of sectionid. I would really appreciate if you help me what to do next I have searched but I'm not understanding anything.
[HttpPost]
public ActionResult CheckSectionIDagainststudentID(string sectionID)
{
int x = Int32.Parse(sectionID);
ConnectionManager connManager = new ConnectionManager();
SqlConnection conn = connManager.GetConnection();
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "Select * From Student Where sectionid = " + x;
cmd.Connection = conn;
conn.Open();
cmd.ExecuteNonQuery();
}
Although you MIGHT be close (not knowing all your tables), I would finish what you have using a SqlDataAdapter. That does a bunch of the work for you when loading into a table.
replace your "cmd.ExecuteNonQuery()" line with something like.
var sda - new SqlDataAdapter();
sda.Command = cmd;
var tbl = new DataTable();
sda.Fill( tbl );
This should pull down all records and put into a datatable object for you. Then you can go through each record and do whatever you need.
Also, fix your parameters. if expecting a number, do so. But from a web post, everything comes in as string and you need to parse as you have done. use int.TryParse() command (read up on that), to prevent crash if some bad text comes in unexpectedly.
Finally fix your query now and all future to prevent sql-injection. use place-holders and then your parameter, such as
cmd.CommandText = "Select * From Student Where sectionid = #parmSectionID";
cmd.Parameters.AddWithValue( "parmSectionID", x );
Dont add the "#" to the string representation in the parameters line.
Definitely read-up on more SQL commands throughout S/O and also SQL-Injection especially this early on in your development. Dont start with bad techniques that will bite you in the long run.

Return on my function doesn't work if using sql

I am populating a text box with the returned value of a function, but it doesn't work if I run the sql code inside the function. I can remove the sql related code and it works. so i'm stumped.
And by "doesn't work" i mean that the text box never gets populated with anything. it remains blank.
thanks
public string CreateResident()
{
string result = "hmm";
SqlConnection sqlConnection = new SqlConnection("Server=DELLXPS\\SQLEXPRESS; Initial Catalog=Warren_SEINDATASYSTEMS; Integrated Security=true;");
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "INSERT INTO [dbo].[NewUsers]([ResidentAccountNumber],[ResidentName],[ResidentAddress],[NumberOfVisitors],[TempPass],[Role])VALUES(#ResidentAccountNumber,#ResidentName,#ResidentAddress,#NumberOfVisitors,(select cast((Abs(Checksum(NewId()))%10) as varchar(1)) + char(ascii('a')+(Abs(Checksum(NewId()))%25)) + char(ascii('A')+(Abs(Checksum(NewId()))%25)) + left(newid(),5)),'resident')";
cmd.CommandType = CommandType.Text;
cmd.Connection = sqlConnection;
SqlParameter ResidentAccountNumber = new SqlParameter();
ResidentAccountNumber.ParameterName = "#ResidentAccountNumber";
ResidentAccountNumber.Value = txtboxResidenetAccountNumber.Text.Trim();
cmd.Parameters.Add(ResidentAccountNumber);
SqlParameter ResidentName = new SqlParameter();
ResidentName.ParameterName = "#ResidentName";
ResidentName.Value = txtboxResidentName.Text.Trim();
cmd.Parameters.Add(ResidentName);
SqlParameter ResidentAddress = new SqlParameter();
ResidentAddress.ParameterName = "#ResidentAddress";
ResidentAddress.Value = txtboxResidentAddress.Text.Trim();
cmd.Parameters.Add(ResidentAddress);
SqlParameter NumberOfVisitors = new SqlParameter();
NumberOfVisitors.ParameterName = "#NumberofVisitors";
NumberOfVisitors.Value = txtboxNumberOfVisitors.Text.Trim();
cmd.Parameters.Add(NumberOfVisitors);
try
{
sqlConnection.Open();
result = (string)cmd.ExecuteScalar();
sqlConnection.Close();
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
protected void btnCreateResident_Click(object sender, EventArgs e)
{
txtboxTempPassword.Text = CreateResident();
}
Your SQL is wrong and you have a lot of problems but I want to show you a way to make your code more readable. Format it like this:
cmd.CommandText = #"INSERT INTO [dbo].[NewUsers] ([ResidentAccountNumber],[ResidentName],[ResidentAddress], NumberOfVisitors],[TempPass], Role])
VALUES(
#ResidentAccountNumber,
#ResidentName,
#ResidentAddress,
#NumberOfVisitors,
(select cast((Abs(Checksum(NewId()))%10) as varchar(1)) + char(ascii('a')+(Abs(Checksum(NewId()))%25)) + char(ascii('A')+(Abs(Checksum(NewId()))%25)) + left(newid(),5)),
'resident')";
cmd.CommandType = CommandType.Text;
cmd.Connection = sqlConnection;
We know that a select in a VALUES constructor is not legal so that is one problem.
Also having a SELECT without a from seems strange -- did you copy your code correctly?
You are using ExecuteScalar -- do you know what that does? It shouldn't include a query that includes INSERT query.
I'm guessing you probably want a stored procedure.
I would suggest do not write query in C# code, you must use Stored Procedure for the same purpose.
If you want your query to return some id, primary key or some value then you must write query for that after your insert query.
you can use the following keywords in your select query,if you want to return id from table.
SCOPE_IDENTITY returns the last IDENTITY value inserted into an IDENTITY column in the same scope.
IDENT_CURRENT returns the last identity value generated for a specific table in any session and any scope.
##IDENTITY returns the last identity value generated for any table in the current session, across all scopes.
If you want to return only one record then use ExecuteScalar else you can use ExecuteReader.
If your only purpose is to insert data into the table then you should use ExecuteNonQuery.
With the help of comments I went with ExecuteReader instead of the ExecuteScaler. And changed the statement to return a value
INSERT INTO [table] ([fields]) OUTPUT Inserted.MyColumn VALUES(values)
C# Code:
reader = cmd.ExecuteReader();
try
{
while (reader.Read())
{
result = reader[0].ToString();
}
}
catch (Exception ex)
{
result = ex.Message;
}
return result;

Insert query inside for loop not working correctly

I am working on Asp .Net project. So I have a page where I am generating random coupon keys. So user enters quantity and generate.
So what I did, I put a for loop according to quantity and inside the for loop I created a random key and search for the key in DB (key is unique) and then insert the data in DB.
Code:
for (int i = 0; i < quantity; i++)
{
do
{
couponKey = generateKey();
} while (!SearchEpinKey(couponKey));
conn = new SqlConnection(connString);
conn.Open();
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
string query = "INSERT INTO CouponStock (coupon_key, status, created_on)";
query += "VALUES('" + couponKey + "','Unused', GETDATE())";
cmd.CommandText = query;
cmd.ExecuteNonQuery();
}
conn.Close();
}
Inside the loop, Flow is like:
-Genrate random key
-Search if random key exists or not in db
-If found similar then again generate random key
-Insert the data in DB
So when I run this page for smaller quantities like 10 or 15, its working fine. But when I go for 50 or 100 its inserting random number of rows like sometime 24, sometime 48. And application get hangs after this. I am thinking that Sql server is hitting numerous time in short interval. Any guidance on how to handle this will be helpful.
The only reason I could find is because of this
do
{
couponKey = generateKey();
} while (!SearchEpinKey(epinKey));
If you are using couponKey in your INSERT query, why do you use SearchEpinKey(epinKey)? where are you searching for couponKey in DB?
You are assigned generateKey() to couponKey variable, and your are checking against epinKey, I believe that when epinKey is already stored in DB it hangs (an infinite loop), because epinKey is always the same even if you assing a new value to couponKey
just change this line
} while (!SearchEpinKey(epinKey));
to this
} while (!SearchEpinKey(couponKey));
First thing first I think we should avoid opening a new connection on every insert, also we should always use ASP.Net build in function for parameter (e.g. AddWithValue), as they help avoid SQL Injection
var couponList = new System.Collections.Generic.List<String>();
var query = "INSERT INTO CouponStock(coupon_key, status, created_on) VALUES(#coupon_key, #status, GETUTCDATE());";
using (SqlConnection conn = new SqlConnection(connString))
{
try
{
conn.Open();
do{
var couponKey = generateKey();
//return early for readability
if(!SearchEpinKey(couponKey)) continue;
if(couponList.Contains(couponKey)) continue;
//add to coupon list to ensure newly generated key does not duplicate
couponList.Add(couponKey);
SqlCommand cmd = conn.CreateCommand(query);
cmd.Parameters.AddWithValue("#coupon_key", couponKey);
cmd.Parameters.AddWithValue("#status", "Unused");
cmd.ExecuteNonQuery();
}
while (couponList.Count < quantity);
}
catch (Exception e)
{
// handle exceptions or re-throw them...
}
finally
{
conn.Close();
}
}

How to check if mysql table is empty?

How to check if my table is empty from C#?
I have something like:
public MySqlConnection con;
public MySqlCommand cmd;
con = new MySqlConnection(GetConnectionString());
con.Open();
cmd = new MySqlCommand("SELECT * FROM data;", con);
Or I don't need to call SELECT statement?
You can use COUNT(*) with no WHERE close and see if exactly how many rows exist with the result.
Or you can do a SELECT (id) FROM tablename with no WHERE clause and if no rows are returned then the table is empty.
I'll give you an example in C# good luck
public bool checkEmptyTable(){
try
{
MySql.Data.MySqlClient.MySqlCommand com = new MySql.Data.MySqlClient.MySqlCommand();
conn = new MySql.Data.MySqlClient.MySqlConnection("YOUR CONNECTION");
com.Connection = conn;
com.CommandText = "SELECT COUNT(*) from data";
int result = int.Parse(com.ExecuteScalar().ToString());
return result == 0; // if result equals zero, then the table is empty
}
finally
{
conn.Close();
}
}
If 'data' might be a big table you would be better with this (where pkdata is your primary key field)
SELECT COUNT(*) FROM data WHERE pkdata = (SELECT pkdata FROM data LIMIT 1);
This will run very quickly whether you have 0 rows in 'data' or millions of rows. Using SELECT with no WHERE or ORDER BY means it just pulls the first row available, LIMIT 1 stops it getting more than 1.
Maybe something to look for if you have a program that ran very quickly six months ago but now runs like a dog in treacle!
SELECT COUNT(*)
FROM table
WHERE `col_name` IS NOT NULL

Trying to insert date and time in sql server but getting error

What is wrong in the following code? im storing the date n time into datetime field in sql server.
private void button1_Click(object sender, EventArgs e)
{
string d = DateTime.Now.ToShortDateString();
cmd.CommandText = "insert into trans values("+label9.Text+",'d');";
cmd.Connection = con;
con.Open();
int x= cmd.ExecuteNonQuery();
MessageBox.Show("Attendance recorded succesfully");
It is a very bad approach, because it opened for sql-injections. You better use SqlParameter.
cmd.CommandText="insert into trans values(#label, #date)";
cmd.Parameters.AddWithValue("label", int.Parse(label9.Text));
cmd.Parameters.AddWithValue("date", DateTime.Now);
cmd.Connection = con;
con.Open();
int x= cmd.ExecuteNonQuery();
There is mistyping in CommandText string. Use this instead
cmd.CommandText="insert into trans values("+label9.Text+","+DateTime.Now.ToString()+");";
EDIT:
Full edited code will be like this. Note that using statements will care for disposing your updates, but this code is still bad and a house of sql-injections. You must use parameters instead if you want safe code.
private void button1_Click(object sender, EventArgs e)
{
using (System.Data.SqlClient.SqlConnection connection = new System.Data.SqlClient.SqlConnection("Data Source=localhost; Initial Datalog=myDatabase; Integrated Security=TRUE;"))
{
using (System.Data.SqlClient.SqlCommand command = new System.Data.SqlClient.SqlCommand("insert into trans values("+label9.Text+","+DateTime.Now.ToString()+");", connection))
{
connection.Open();
command.ExecuteNonQuery();
connection.Close();
}
}
}
Apart from the fact that you are using inline SQL, which is just bad. You should be using #param1 syntax in the query and then adding parameters to it instead (thus sidestepping this issue also). Even better - use an ORM like Linq to Sql or Entity Framework (or nHibernate or whatever).
SQL Server generally wants it's times in yyyymmdd format, and also you really should be checking the label's value is indeed an integer and only running the query if it is:
int labelValue = 0;
if(int.TryParse(label9.Text, out labelValue))
{
cmd.CommandText="insert into trans values("+ labelValue +
", '" + DateTime.Now.ToString("yyyyMMdd");"')";
cmd.Connection = con;
con.Open();
int x= cmd.ExecuteNonQuery();
MessageBox.Show("Attendance recorded succesfully");
}
I'd also say you really need to examine your usage of the connection/command - where do you Dispose? Judging by this code, I'm guessing you don't?
All in all, even with these fixes I'm not recommending you do things this way - do it the way that Harm suggests - the +5 (or more) there is deserved.

Categories

Resources