Insert multiple generated value into table - c#

First thing, my question is quite complicated and I am not really proficient to explain it in details, so I would like to say sorry in advance.
Ok, here is the thing. I execute this query
string count = "SELECT Count(*) FROM Student WHERE IntakeID = 'MYVALUE'"
And it would return the number of 10. So I continue with this code:
SqlCommand cmd = new SqlCommand(count, conn);
int temp = Convert.ToInt32(cmd.ExecuteScalar().ToString());
for (int x = 0; x < temp; x++)
{
string query = "INSERT INTO Docket (DocketNo, StudentID) VALUES ('" + getUniqueKey() + "','(SELECT StudentID FROM Student WHERE IntakeID = 'MYVALUE')')
}
PS: getUniqueKey() is a method to get my generated unique key.
Is this piece of code technically correct? The result I want to have is something like below:
+-----------+-------------+
| DocketNo | StudentID |
+-----------+-------------+
| 18590394 | TP123456 |
| 09141563 | TP012457 |
| 58293495 | TP049185 |
+-----------+-------------+
If you are unclear of my question, I will try my best to make it clearer. Sorry for inconvenience.
UPDATE (ANSWER):
With the help from Paparazzi (Thanks!) for his code, I modified and come up with my own solution.
string count = "SELECT StudentID FROM Student WHERE IntakeID = 'MYVALUE'"
SqlCommand cmd = new SqlCommand(count, conn);
string query = "INSERT INTO Docket (DocketNo, StudentID) VALUES ";
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
if (rdr.HasRows)
{
var loop = true;
while (loop)
{
loop = rdr.Read();
if (!loop)
{
//When end of rows and no more data to be retrieve, it removes the last "," from the query.
char[] trimChar = { ',' };
string newQuery = query.TrimEnd(trimChar);
cmd.CommandText = newQuery;
}
else {
query += "('" + GetUniqueKey() + "','" + rdr.GetString(0) + "')";
query += ",";
}
}
}
cmd.ExecuteNonQuery();
conn.Close();
So actually while looping on the SqlDataReader, the query would generate in the background something like:
INSERT INTO Docket(DocketNo, StudentID) VALUES ('1562456','TP028800'), ('1465446','TP028801'),..........('4939104','TP028810'),
Take note there will be a "," comma at the end of the query because of the query += ",";. And when the SqlDataReader returns no more rows, it would execute the if(!loop) statement to remove the last "," (comma) from the query.
If you are unclear what is the += for, read more at https://msdn.microsoft.com/en-us/library/sa7629ew.aspx
UPDATE 2:
#Paparazzi has come up with a much more efficient and performance-wise method if you are managing a huge data. Look for his code in his own post. :)

string count = "SELECT StudentID FROM Student WHERE IntakeID = 'MYVALUE'"
SqlCommand cmd = new SqlCommand(count, conn);
string query = "INSERT INTO Docket (DocketNo, StudentID) VALUES ";
conn.Open();
bool first = true;
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
if (first)
first = false;
else
query += ", "
query += "('" + getUniqueKey() + "', '" + rdr.GetString(0) + "')";
}
}
if (!first)
{
cmd.CommandText = query + ";";
cmd.ExecuteNonQuery();
}
conn.Close();
StringBuilder is faster than += on string
And multiple values is limited to 1000 (I think) but WAY more efficient than individual inserts
So if you can get more than 1000 then need to add a counter and fire off the insert
string getID = "SELECT StudentID FROM Student WHERE IntakeID = 'MYVALUE'"
SqlCommand cmd = new SqlCommand(getID , conn);
string insert = "INSERT INTO Docket (DocketNo, StudentID) VALUES ";
Int32 count = 0;
StringBuiler sb = new StringBuiler();
conn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
if (count == 0)
{
sb.Clear();
sb.AppendLine(insert);
}
else
sb.Append(", ")
sb.Append("('" + getUniqueKey() + "', '" + rdr.GetString(0) + "')");
count++;
if(count > 800)
{
count = 0;
cmd.CommandText = sb.ToString() + ";";
cmd.ExecuteNonQuery();
// most likely need a separate cmd here has a open reader
// will leave that as an exercise for you
// could even go asynch if you want to get faster
// or you could just build up multiple inserts on sb
}
}
}
if (count > 0)
{
cmd.CommandText = sb.ToString() + ";";
cmd.ExecuteNonQuery();
}
conn.Close();

SqlCommand cmd = new SqlCommand(count, conn);
int temp = Convert.ToInt32(cmd.ExecuteScalar().ToString());
for (int x = 0; x < temp; x++)
{
string query += "INSERT INTO Docket (DocketNo, StudentID) VALUES ('" + getUniqueKey() + "','(SELECT StudentID FROM Student WHERE IntakeID = 'MYVALUE')');";
}
SqlCommand cmd = new SqlCommand(query, conn);
cmd.ExecuteQuery();

Related

Check SQL for Book_Availability before issuing one (BookAvailability-1)

If I put "if, foreach, and else statement under comment //", the program works and Reduces book count by 1 from SQL database. But I want to check IF there is at least 1 available book to give. This code keeps showing me the message in "else" statement if I leave it like this. Help is needed fast, it's my final project, that is needed to be done before 23.07. :(
int book_qty = 0;
SqlCommand cmd2 = connection.CreateCommand();
cmd2.CommandType = CommandType.Text;
cmd2.CommandText = "SELECT * FROM Book_list WHERE BookName = '" + TextBoxBookName + "'";
cmd2.ExecuteNonQuery();
DataTable dt2 = new DataTable();
SqlDataAdapter da2 = new SqlDataAdapter(cmd2);
da2.Fill(dt2);
foreach (DataRow dr2 in dt2.Rows)
{
book_qty = Convert.ToInt32(dr2["book_qty"].ToString());
}
if (book_qty > 0)
{
SqlCommand cmd = connection.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO Issue_book VALUES(" + TextBoxSearchMembers.Text + ",'" + TextBoxMemberName.Text + "','" + TextBoxMemberContact.Text + "','" + TextBoxMemberEmail.Text + "','" + TextBoxBookName.Text + "', '" + DateTimePicker1.Text + "')";
cmd.ExecuteNonQuery();
SqlCommand cmd1 = connection.CreateCommand();
cmd1.CommandType = CommandType.Text;
cmd1.CommandText = "UPDATE Book_list SET BookAvailability = BookAvailability-1 WHERE BookName ='" + TextBoxBookName.Text + "'";
cmd1.ExecuteNonQuery();
MessageBox.Show("successful issue");
this.Close();
else
{
MessageBox.Show("Book not available");
}
You are only checking book_qty from the last row in your result set instead of BookAvailability for all rows. You probably want to do something like:
SqlCommand cmd2 = connection.CreateCommand();
cmd2.CommandType = CommandType.Text;
cmd2.CommandText = "SELECT BookAvailability FROM Book_list WHERE BookName = '" + TextBoxBookName + "'";
var result = cmd2.ExecuteScalar();
book_qty = Convert.ToInt32(result);
You need to make sure that there is only one book with the given bookname available.
In that case just correcting this one line in your code would help as well:
book_qty = Convert.ToInt32(dr2["book_qty"].ToString());
to
book_qty = Convert.ToInt32(dr2["BookAvailability"].ToString());
Otherwise you'd need to query SUM(BookAvailability), but the following code would decrease the amount of books for multiple books at once, that wouldn't be good.
Untested code. I don't have your database. Comments and explanation in line.
private void OPCode()
{
try
{
//keep your connections close to the vest (local)
using (SqlConnection connection = new SqlConnection())
//a using block ensures that your objects are closed and disposed
//even if there is an error
{
using (SqlCommand cmd2 = new SqlCommand("SELECT BookAvailability FROM Book_list WHERE BookName = #BookName", connection))
{
//Always use parameters to protect from sql injection
//Also it is easier than fooling with the single quotes etc.
//If you are referring to a TextBox you need to provide what property is
//being accessed. I am not in a WPF right now and not sure if .Text
//is correct; may be .Content
//You need to check your database for correct data type and field size
cmd2.Parameters.Add("#BookName", SqlDbType.VarChar, 100).Value = TextBoxBookName.Text;
//A select statement is not a non-query
//You don't appear to be using the data table or data adapter
//so dump them extra objects just slow things dowm
connection.Open();
//Comment out the next 2 lines and replaced with
//Edit Update
//var returnVal = cmd2.ExecuteScalar() ?? 0;
//if ((int)returnVal > 0)
//*************************************************************
//Edit Update
//*************************************************************
//in case the query returns a null, normally an integer cannot
//hold the value of null so we use nullable types
// the (int?) casts the result of the query to Nullable of int
Nullable<int> returnVal = (int?)cmd2.ExecuteScalar();
//now we can use the .GetValueOrDefault to return the value
//if it is not null of the default value of the int (Which is 0)
int bookCount = returnVal.GetValueOrDefault();
//at this point bookCount should be a real int - no cast necessary
if (bookCount > 0)
//**************************************************************
//End Edit Update
//**************************************************************
{
using (SqlCommand cmd = new SqlCommand("INSERT INTO issue_book VALUES(#SearchMembers etc", connection))
{
//set up the parameters for this command just like the sample above
cmd.Parameters.Add("#SearchMembers", SqlDbType.VarChar, 100).Value = TextBoxSearchMembers.Text;
cmd.ExecuteNonQuery();
}
using (SqlCommand cmd1 = new SqlCommand("UPDATE Book_list SET BookAvailability = BookAvailability-1 WHERE BookName = #BoxBookName;", connection))
{
cmd1.Parameters.Add("#BoxBookName", SqlDbType.VarChar, 100);
cmd1.ExecuteNonQuery();
}
MessageBox.Show("success");
this.Close();
}
else
{
MessageBox.Show("Book not available");
}
}
}
}
catch (Exception exc)
{
MessageBox.Show(exc.ToString());
}
}

How do I check Duplicate [duplicate]

This question already has an answer here:
how to i search if there is a same id in a database?
(1 answer)
Closed 6 years ago.
private void Add_Box_Click(object sender, EventArgs e)
{
string phoneNumber;
if (string.IsNullOrWhiteSpace(Id_Box.Text))// To check if the Id_box is empty or not
{
MessageBox.Show("Please Enter Your ID");// need to enter ID in order to save data
}
///////////////////////////////////////////check the Extension Box////////////////////////////////////////////////////////////////////////////////////
else
{
if (string.IsNullOrWhiteSpace(Ext_Box.Text))
{
phoneNumber = Phone_Box.Text;// if it is empty then it will only show the phone number
}
else
{
phoneNumber = Phone_Box.Text + "," + Ext_Box.Text; // show the phone number and the extension if there is something in the extension
}
///////////////////////////////////////////////////////////Save it to the Database///////////////////////////////////////////////////////
SqlCeCommand cmd = new SqlCeCommand("INSERT INTO Contact_List(Id, Name, Adress1, Adress2, City, Province, Postal_Code, Phone, Email)VALUES('" + Id_Box.Text + "','" + Name_Box.Text + "','" + Adress1_Box.Text + "','" + Adress2_Box.Text + "','" + City_Box.Text + "','" + Province_Box.Text + "','" + Code_Box.Text + "','" + phoneNumber + "','" + Email_Box.Text + "')", con);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
MessageBox.Show("Information Added", "Confirm");
/////////////////////////////////////Show new set of data after insert a new data/////////////////////////////////////////////////////////////
SqlCeCommand cmd2 = new SqlCeCommand("Select * from Contact_List;", con);
try
{
SqlCeDataAdapter sda = new SqlCeDataAdapter();
sda.SelectCommand = cmd2;
DataTable dt = new DataTable();
sda.Fill(dt);
BindingSource bs = new BindingSource();
bs.DataSource = dt;
dataGridView1.DataSource = bs;
sda.Update(dt);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
////////////////////////////////Empty The Box/////////////////////////////////////////////////////////////////////////////////////////////////
Id_Box.Text = String.Empty;
Name_Box.Text = String.Empty;
Adress1_Box.Text = String.Empty;
Adress2_Box.Text = String.Empty;
City_Box.Text = String.Empty;
Province_Box.Text = String.Empty;
Code_Box.Text = String.Empty;
Phone_Box.Text = String.Empty;
Ext_Box.Text = String.Empty;
Email_Box.Text = String.Empty;
}
}
This code will store Id, name, etc to the database. But when there is a same Id, i want to delete it. When i delete it both of the same Id will be deleted and i don't want that so is there anyway to check duplicate before it store it to the database?
I want to do something like this if possible :
if ( the values in id column == to the Id_textBox) {
MessageBox.Show("Duplicate ,PLease enter anotherId")
}
Possible?
Before executing your INSERT SQL statement, try running the SQL int ContactCount = (int)cmd.ExecuteScalar("SELECT COUNT(*) FROM CONTACT_LIST WHERE Id = '" + Id_Box.Text + "'")
If ContactCount > 0 then you can do the DELETE your suggesting.
Can I also recommend that you use a SQL UPDATE instead of DELETEing and INSERTing the same record.
Also, read-up on SQL Injection attacks. Building a SQL statement, like you're doing here, using the values input by a user leaves you exposed to that type of vulnerability.
First of all, like in all these answers: Don't use string concatenation but parametrized queries to prevent SQL-injection.
For your problem:
You can either do a
string query = "SELECT count(*) from ContactList Where id = #id";
SqlCeCommand cmd = new SqlCeCommand(query, connection);
cmd.Parameters.Add("#id", SqlDbType.NVarChar, 50).Value = Id_Box.Text;
int count = (int)cmd.ExecuteScalar();
if count > 0 the id already exists.
Or you can do a
string query "IF NOT EXISTS(SELECT count(*) from ContactList Where id = #id) INSERT INTO ContactList(Id, ...) VALUES(#id, ...)";
SqlCeCommand cmd = new SqlCeCommand(query, connection);
cmd.Parameters.Add("#id", SqlDbType.NVarChar, 50).Value = Id_Box.Text;
int count = cmd.ExecuteNonQuery();
count will then contain the number of rows affected, ie 0 if the value already existed, or 1 if it did not exist, but was newly inserted.

how to display count in label text?

i am having a hard time to display my count code to my label text. here is my code and please tell me how to solve this problem.
ordering_and_billing.dBase dBase = new ordering_and_billing.dBase();
var mydbconnection = new dBase.dbconnection();
string sql = "SELECT * FROM `order` WHERE eventdate='" + lbldte.Text + "'";
MySqlCommand cmd = new MySqlCommand(sql, mydbconnection.Connection);
mydbconnection.Connection.Open();
MySqlDataReader rdr = cmd.ExecuteReader();
if (rdr.HasRows)
{
while (rdr.Read())
{
Int32 count = (Int32)cmd.ExecuteScalar();
string disp = count.ToString();
lblcount.Text = disp;
}
}
just use count function:
string sql = "SELECT COUNT(*) FROM `order` WHERE eventdate='" + lbldte.Text + "'";
also don't use ExecuteReader, use ExecuteScalar function if you want a single value like a count value:
lblcount.Text =cmd.ExecuteScalar().toString();
You should use SELECT COUNT(*) if all you want is the record count.
string sql = "SELECT COUNT(*) FROM `order` WHERE eventdate='" + lbldte.Text + "'";
However, keep in mind that rdr.Read() reads a new row from the sql query. Every time you get a new row, you're trying to rerun the sql command (which I'm guessing crashes) and then assign the count label. So you're trying to assign the count label count times. Use this construct instead:
int count = 0;
while (rdr.Read())
{
count++;
}
lblcount.Text = count.ToString(); //only assigns to the Text property once
never mind guys i got my answer now.
ordering_and_billing.dBase dBase = new ordering_and_billing.dBase();
var mydbconnection = new dBase.dbconnection();
string sql = "SELECT * FROM `order` WHERE eventdate='" + lbldte.Text + "'";
MySqlCommand cmd = new MySqlCommand(sql, mydbconnection.Connection);
mydbconnection.Connection.Open();
MySqlDataReader rdr = cmd.ExecuteReader();
int count = 0;
while (rdr.Read())
{
count ++;
}
lblcount.Text = count.ToString();

data reader has rows but comparison of its values is never true

I am creating a module for booking rooms in hotel.After selecting the rooms, the room numbers appear in a label. On clicking the OK button, the following code executes. When I am checking the availability of rooms, even if it is "No", flag does'nt get initialized to 1. Can anyone guide me where am I going wrong.
protected void ok_room(object sender, EventArgs e)
{
if (Label1.Text != "")
{
int result = 0;
int flag = 0;
string[] room = Label1.Text.Split(new char[] { ' ' });
cmd = new SqlCommand();
cmd1 = new SqlCommand();
cmd1.Connection = con;
cmd.Connection = con;
for (int i = 0; i < room.Length; i++)
{
cmd1.CommandText = "select room_availability from rooms where room_num='" + room[i] + "' ";
dr = cmd1.ExecuteReader();
while (dr.Read())
{
if (dr[0].ToString().Equals("No"))//this is not working
flag = 1;
}
dr.Close();
}
Response.Write(flag);
if (flag == 0)
{
for (int i = 0; i < room.Length; i++)
{
cmd.CommandText = "update rooms set room_availability='No' where room_num='" + room[i] + "'";
cmd.ExecuteNonQuery();
result = 1;
}
}
else
{
Label2.Text = "Some of the selected rooms are not available. Kindly try again";
Label1.Visible=false;
}
if (result == 1)
{
isRoomAvailable = true;
Label2.Text = " Room(s) " + Label1.Text + " is/are booked";
Label1.Visible = false;
}
}
else
Response.Write("<script>alert('Select a room first.')</script>");
}
I would do more of the logic in SQL, this would simplify the code:
// Create a condition looking like this: room_num IN('1', '2', '3')
string roomsCondition = "room_num IN (' + Label1.Text.Replace(" ", "', '") + "')";
cmd1.CommandText =
#"SELECT SUM(CASE WHEN room_availability='Yes' THEN 1 ELSE 0 END) As available,
SUM(CASE WHEN room_availability='No' THEN 1 ELSE 0 END) As not_available
FROM rooms WHERE " + roomsCondition;
This query returns the number of available and non available rooms. It should then be easier to formulate the logic than by the use of flags.
Also have a look at the ExecuteScalar method. It makes it even easier than with the query I have shown above:
using (SqlConnection conn = new SqlConnection(connString)) {
string sql = "SELECT COUNT(*) FROM rooms WHERE room_availability='Yes' AND " +
roomsCondition;
SqlCommand cmd = new SqlCommand(sql, conn);
conn.Open();
int availableRooms = (int)cmd.ExecuteScalar();
if (availableRooms > 0) {
cmd.CommandText =
#"UPDATE rooms
SET room_availability='No'
WHERE availability='Yes' AND " + roomsCondition;
cmd.ExecuteNonQuery();
} else {
...
}
}

SCOPE_IDENTITY is not working in asp.net?

I am trying to insert a record and get its newly generated id by executing two queries one by one, but don't know why its giving me the following error.
Object cannot be cast from DBNull to other types
My code is as below: (I don't want to use sql stored procedures)
SqlParameter sqlParam;
int lastInsertedVideoId = 0;
using (SqlConnection Conn = new SqlConnection(ObjUtils._ConnString))
{
Conn.Open();
using (SqlCommand sqlCmd = Conn.CreateCommand())
{
string sqlInsertValues = "#Name,#Slug";
string sqlColumnNames = "[Name],[Slug]";
string sqlQuery = "INSERT INTO videos(" + sqlColumnNames + ") VALUES(" + sqlInsertValues + ");";
sqlCmd.CommandText = sqlQuery;
sqlCmd.CommandType = CommandType.Text;
sqlParam = sqlCmd.Parameters.Add("#Name", SqlDbType.VarChar);
sqlParam.Value = txtName.Text.Trim();
sqlParam = sqlCmd.Parameters.Add("#Slug", SqlDbType.VarChar);
sqlParam.Value = txtSlug.Text.Trim();
sqlCmd.ExecuteNonQuery();
//getting last inserted video id
sqlCmd.CommandText = "SELECT SCOPE_IDENTITY() AS [lastInsertedVideoId]";
using (SqlDataReader sqlDr = sqlCmd.ExecuteReader())
{
sqlDr.Read();
lastInsertedVideoId = Convert.ToInt32(sqlDr["lastInsertedVideoId"]);
}
}
}
//tags insertion into tag table
if (txtTags.Text.Trim().Length > 0 && lastInsertedVideoId > 0)
{
string sqlBulkTagInsert = "";
string[] tags = txtTags.Text.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (string tag in tags)
{
sqlBulkTagInsert += "INSERT INTO tags(VideoId, Tag) VALUES(" + lastInsertedVideoId + ", " + tag.Trim().ToLowerInvariant()+ "); ";
}
using (SqlConnection Conn = new SqlConnection(ObjUtils._ConnString))
{
Conn.Open();
using (SqlCommand sqlCmd = Conn.CreateCommand())
{
string sqlQuery = sqlBulkTagInsert;
sqlCmd.CommandText = sqlQuery;
sqlCmd.CommandType = CommandType.Text;
sqlCmd.ExecuteNonQuery();
}
}
}
And also if possible, please check is the above code coded well or we can optimize it more for improve performance?
Thanks
The call to SCOPE_IDENTITY() is not being treated as being in the same "scope" as the INSERT command that you're executing.
Essentially, what you need to do is change the line:
string sqlQuery = "INSERT INTO videos(" + sqlColumnNames + ") VALUES(" + sqlInsertValues + ");";
to:
string sqlQuery = "INSERT INTO videos(" + sqlColumnNames + ") VALUES(" + sqlInsertValues + "); SELECT SCOPE_IDENTITY() AS [lastInsertedVideoId]";
and then call
int lastVideoInsertedId = Convert.ToInt32(sqlCmd.ExecuteScalar());
instead of .ExecuteNonQuery and the code block following the "//getting last inserted video id" comment.
The SCOPE_IDENTITY() should be extracted from the first command (SELECT, RETURN or OUT) and passed into the next command. By that, I mean that the SELECT_IDENTITY() should be at the end of the first command. In SQL 2008 there is additional syntax for bring values back as part of the INSERT, which makes this simpler.
Or more efficiently: combine the commands into one to avoid round-trips.

Categories