I tried everything I could knew on this, basically I have a table of Clients ( Sql Server )
The table looks like this
create table Client
(
Name nvarchar(100),(I want to be null)
EmployeesNo nvarchar(50),
CompanyCapital int
)
This simple table, the problem I encounter is when I want to update.
The problem is I can have multiple data with same values in Name so how to differentiate between the Values in Name to make them unique, Update looks like:
using(SqlConnection con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Data"].ToString())
{
if(con.State.ToString() == "Closed")
{
con.Open();
}
using(SqlCommand com = new SqlCommand("Update Client set Name = #name, EmployeesNo = #emp, CompanyCapital = #com where Name = #name2 (Should I update by some another thing that it will make it unique ???)",con))
{
com.Parameters.Add(new SqlParameter("#name2",Mod));(Mod = string I initialized in constructor from another form;)
com.Parameters.Add(new SqlParameter("#name",textBox1.Text));
com.Parameters.Add(new SqlParameter("#emp",textBox2.Text));
com.Parameters.Add(new SqlParameter("#com",textBox3.Text));
com.ExecuteNonQuery();
}
}
So when i update or user updates those values if i have multiple data with same values it will overwrite all of them and i don't want that, remember also that values are inserted and updated from textboxes.
I tried thinking of using Primary key but how do i know where to update at wich primary key, cause im using textboxes and i don't want the user to type in the ID of something, thanks.
You should use a primary key (like ID) if you need to uniquely identify your records.
In order to know the ID of the record that needs to be updated, just store the ID in your form as a hidden and readonly field.
The second parameter of Parameters.Add method, its SqlDbType. Not the Parameter Value.
instead use Parameters.AddWithValue
or put value in object initializer,
com.Parameters.Add(new SqlParameter("#name2", SqlDbType.VarChar) {Value = Mod});
Related
I'm trying to update a database table with values from listbox as well as textbox values however and exception was thrown
Exception.
Procedure or function expects parameter, which was not supplied.
thrown even after supplying the parameter. I wanted the courses selected to be shown in the same column of database table separated by comma.
This is what I have so far.
using (SqlCommand com = new SqlCommand("updateStudent", connection))
{
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddWithValue("#studentNum", studentNum.Text);
com.Parameters.Add("#studentName", SqlDbType.NVarChar).Value = studentName.Text;
foreach (ListItem item in lstCourse.Items)
{
if (item.Selected)
{
com.Parameters.Add("#courses", SqlDbType.NVarChar).Value = " " + item.Text + " ";
}
}
com.ExecuteNonQuery();
com.Parameters.Clear();
}
}
The Error is normal
You can not send more than once a parameter with the same name for the invocation of a stored procedure.
If you need to save a list of courses to the student entity, you must change the structure of the database, and use a new table with a foreign key to the student table.
Check this documentation
Foreing Key ,
Store Procedure
I think #Vinit had the right answer to do what you want to do. In place of your foreach (ListItem item in lstCourse.Items) you want this instead.
// create comma separated list of selected courses
var courses = string.Join(",", lstCourse.Items
.Where(item=>item.Selected)
.Select(s=>s.Text)
.ToList());
// add courses as parameter
com.Parameters.Add("#courses", SqlDbType.NVarChar).Value = courses;
It builds the list of comma separated course names and then puts that into the command as one argument #courses.
However!! After having done this for around 20 years I can tell you you're not really going to like it this way. You're going to want the courses that the student selected to be in separate records. Each time you have to deal with these courses you're going to deal with this collection of course names.
What I have done in this case is create a separate table to join Student to Course in a "Many to Many" relationship.
BTW - I don't see the place in your code where you tell the command what SP to execute.
Mike
Instead of foreach loop, you should do
// create comma separated list of selected courses
var courses = string.Join(",", lstCourse.Items
.Where(item=>item.Selected)
.Select(s=>s.Text)
.ToList());
// add courses as parameter
com.Parameters.Add("#courses", SqlDbType.NVarChar).Value = courses;
UPDATE
After reading through your one of the comments where you have shared the procedure code below.
update Student
set studentNum=#studentNum,studentName=#studentName,courses=#courses
where studentId=#studentId`
it seems you are not passing the #studentId as parameter. that might be the reason for error message
Procedure or function expects parameter, which was not supplied.
So you should add this parameter to sql command
com.Parameters.Add("#studentId", SqlDbType.Int).Value = studentId; -- update the dbtype and variable as per your system.
This is my first time posting, so please let me know if I made a mistake or if my question is poorly worded. I am currently working on an utility app that allows data from several different csv files to be uploaded into a database for reporting purposes.The App takes the files, combines them, and removes duplicates. Once the database is generated any new file can be uploaded to update the database or insert new records.
I looked around and I couldn't find a solution for my problem. At the moment I am having trouble updating the database with new data.
For some reason, whenever I try to update the data using the following stored procedure, none of the changes are saved in the database.
CREATE PROCEDURE [dbo].[UpdateDeviceReport]
#SerialNumber AS VARCHAR(32),
#DeviceType AS VARCHAR(8),
#InstalledOn AS VARCHAR(32),
#PortStatus AS CHAR(6)
AS
BEGIN
UPDATE computer
SET deviceType = #DeviceType, deviceInstalledOn = #InstalledOn
WHERE serialID = #SerialNumber
UPDATE computer_localblocker
SET portStatus = #PortStatus
WHERE computer_serialid = #SerialNumber;
END
GO
Here is the C# code that executes the procedure.
public void updateOrgDevices()
{
using (var conn = new SqlConnection(PopulateDatabase.connectionString))
{
int debug = 0;
conn.Open();
foreach (KeyValuePair<string, DictionaryObjs> element in GlobalVariables.UpdateData)
{
OrgDevRepObj obj = element.Value as OrgDevRepObj;
SqlCommand sqlCommand = new SqlCommand("UpdateDeviceReport", conn);
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.Add("#SerialNumber", SqlDbType.VarChar, 32).Value = obj.SerialNumber.Trim().ToUpper();
sqlCommand.Parameters.Add("#DeviceType", SqlDbType.VarChar, 8).Value = obj.DeviceType;
sqlCommand.Parameters.Add("#InstalledOn", SqlDbType.VarChar, 32).Value = obj.InstalledOn;
sqlCommand.Parameters.Add("#PortStatus", SqlDbType.Char, 6).Value = obj.PortStatus;
debug = sqlCommand.ExecuteNonQuery();
}
}
}
The parameters come from a dictionary/hashmap, GlobalVariables.UpdateData, that stores data rows as objects where the key is the serial number from that row of data(e.g. Dictionary<string[serial Number], DictionaryObjs>) and the values of the fields for each data row are stored as strings, in a class called DictionaryObjs. This is the parent class for all record types. In this case the record type is OrgDevRepObj.
I was able to get the code to work once, but I haven't been able to replicate it. It doesn't throw any errors, but I know its not working because sqlCommand.ExecuteNonQuery(); returns a -1 for each dictionary key value pair. I've also tried using
sqlCommand.Parameters.AddWithValue('#Param', [value]);
Any ideas?
Could you possibly have set NOCOUNT ON globally? See msdn.microsoft.com/en-us/library/ms176031.aspx
Try adding SET NOCOUNT OFF to your stored procedure.
An idea to test according to your situation, create a table called test with a single varchar type field and inside the procedure you make an insert to that table by inserting the SerialNumber. This way you can tell if it is filtering by the correct serial and if the procedure is executed. Luckā¦
I am importing data from large excel sheet and storing it in a stateTable. Now I have to push this data into a database table. The table does have an identity column(1,1).
I have created a similar table type in DB and a procedure to take a parameter as table type to insert in the particular table. I have also set ON the identity insert.
My code is:
using (SqlCommand command = new SqlCommand("InsertStateTable") {
CommandType = CommandType.StoredProcedure})
{
SqlParameter param = command.Parameters.AddWithValue("#statetable", dt);
param.TypeName = "StateTable";
param.SqlDbType = SqlDbType.Structured;
command.Connection = con;
con.Open();
command.ExecuteNonQuery();
con.Close();
}
But the error that arises is
"INSERT into an identity column not allowed on table variables."
I have gone thru many sites but no specific reason is given.....
Thanks in advance.
The error is fairly clear: you are not allowed to do what you are trying to do. Basically, you are going to have to find a design that is not dependent on inserting the identity value into the table-variable / table-valued-parameter. My advice would be to create a separate table-variable (unrelated to the table-valued-parameter) which has the same data, but which does not have the IDENTITY column, so...
declare #foo table (id int not null, name nvarchar(200) not null /* etc */)
insert #foo (id, name /* etc */)
select id, name /* etc */ from #statetable
at which point #foo has the original data, but does not have an identity column - you can then do whatever you want with #foo.
Without seeing what you are doing with your identity insert, it is hard to comment much further.
I have been trying to use OleDbDataAdapter to update a DataTable but got confused about the commands.
Since I sometimes get info from diffrent tables I can't use a CommandBuilder.
So I have tried to create the commands on my on but found it hard with the parameters.
DataTable.GetChanges returns rows that needs to use an INSERT or an UPDATE command - I guess I can't distinct between them.
I need you to complete the following:
DataTable dt = new DataTable();
OleDbDataAdapter da = new OleDbDataAdapter();
// Here I create the SELECT command and pass the connection.
da.Fill(dt);
// Here I make changes (INSERT/UPDATE) to the DataTable (by a DataGridView).
da.UpdateCommand = new OleDbCommand("UPDATE TABLE_NAME SET (COL1, COL2, ...) VALUES (#newVal1, #newVal2, ...) WHERE id=#id"); // How can I use the values of the current row (that the da is updating) as the parameters (#newVal1, #newVal2, id....)?
Thank you very much!
The data adapter can work in conjunction with the datatable. As such, I've actually wrapped mine together into a class and works quite well. Aside from the complexities of my stuff, here's a snippet that might help you along. When adding a parameter, you can identify the column source that the data is coming from FROM the DataTable. This way, when a record is internally identified as "Added" or "Updated" (or "Deleted"), when you build your SQL Insert/Update/Delete commands, it will pull the data from the columns from the respective rows.
For example. Say I have a DataTable, primary Key is "MyID" and has columns "ColX, ColY, ColZ". I create my DataAdapter and build out my select, update, delete commands something like... (? is a place-holder for the parameters)
DataAdapter myAdapter = new DataAdapter()
myAdapter.SelectCommand = new OleDbCommand();
myAdapter.InsertCommand = new OleDbCommand();
myAdapter.UpdateCommand = new OleDbCommand();
myAdapter.DeleteCommand = new OleDbCommand();
myAdapter.SelectCommand.CommandText = "select * from MyTable where MyID = ?";
myAdapter.InsertCommand.CommandText = "insert into MyTable ( ColX, ColY, ColZ ) values ( ?, ?, ? )";
myAdapter.UpdateCommand.CommandText = "update MyTable set ColX = ?, ColY = ?, ColZ = ? where MyID = ?";
myAdapter.DeleteCommand.CommandText = "delete from MyTable where MyID = ?";
Now, each has to have their respective "Parameters". The parameters have to be addded in the same sequence as their corresponding "?" place-holders.
// Although I'm putting in bogus values for preparing the parameters, its just for
// data type purposes. It does get changed through the data adapter when it applies the changes
OleDbParameter oParm = new OleDbParameter( "myID", -1 );
oParm.DbType = DbType.Int32;
oParm.SourceColumn = "myID"; // <- this is where it looks back to source table's column
oParm.ParameterName = "myID"; // just for consistency / readability reference
myAdapter.SelectCommand.Parameters.Add( oParm );
do similar for rest of parameters based on their types... char, int, double, whatever
Again, I have like a wrapper class that handles managment on a per-table basis... in brief
public myClassWrapper
{
protected DataTable myTable;
protected DataAdapter myAdapter;
... more ...
protected void SaveChanges()
{
}
}
Its more complex than just this, but during the "SaveChanges", The datatable and dataAdapter are in synch for their own purposes. Now, flushing the data. I check for the status of the table and then you can pass the entire table to the dataAdapter for update and it will cycle through all changed records and push respective changes. You'll have to trap for whatever possible data errors though.
myAdapter.Update( this.MyTable );
As it finds each "changed" record, it pulls the values from the Column Source as identified by the parameter that is found in the table being passed to the adapter for processing.
Hopefully this has given you a huge jump on what you are running into.
---- COMMENT PER FEEDBACK ----
I would put your update within a try/catch, and step into the program to see what the exception is. The message adn/or inner exception of the error might give more info. However, try to simplify your UPDATE to only include a FEW fields with the WHERE "Key" element.
Additionally, and I oopsed, missed this from first part answer. You might have to identify the datatable's "PrimaryKey" column. To do so, its a property of the DataTable that expects and array of columns that represent the primary key for the table. What I did was...
// set the primary key column of the table
DataColumn[] oCols = { myDataTbl.Columns["myID"] };
myDataTbl.PrimaryKey = oCols;
I would comment out your full update string and all its parameters for your UPDATE. Then, build it with just as simple as my sample of only setting 2-3 columns and the where clause
myAdapter.UpdateCommand.CommandText = "update MyTable set ColX = ?, ColY = ? where MyID=?";
Add Parameter object for "X"
Add Parameter object for "Y"
Add Parameter object for "MyID"
Pick fields like int or char so they have the least probability of problems for data type conversions, then, once that works, try adding all your "int" and "character" columns... then add any others. Also, which database are you going against. SOME databases don't use "?" as placeholder in the command but use "named" parameters, some using
"actualColumn = #namedCol"
or even
"actualColumn = :namedCol"
Hope this gets you over the hump...
You could use the String.Format Method to replace the #newVal1, #newVal2, ... in your code, like this da.UpdateCommand = new OleDbCommand(String.Format("UPDATE TABLE_NAME SET (COL1, COL2, ...) VALUES ({0}, {1}, ...) WHERE id=#id",OBJECT_ARRAY_CONTAINING_VALUES_FROM_THEDG));
[Eidt per comment]
To handle the row[0], row[1] you need a loop like:
for(i=0; i<rows.Count; i++)
{
da.UpdateCommand = new OleDbCommand(String.Format("UPDATE...",row[i]);
da.Update(dt);
}
I know that in Oracle I can get the generated id (or any other column) from an inserted row as an output parameter.
Ex:
insert into foo values('foo','bar') returning id into :myOutputParameter
Is there a way to do the same, but using ExecuteScalar instead of ExecuteNonQuery?
I don't want to use output parameters or stored procedures.
ps: I'm using Oracle, not sql server!!!
If you are on oracle, you have to use ExecuteNonQuery and ResultParameter. There is no way to write this as query.
using (OracleCommand cmd = con.CreateCommand()) {
cmd.CommandText = "insert into foo values('foo','bar') returning id into :myOutputParameter";
cmd.Parameters.Add(new OracleParameter("myOutputParameter", OracleDbType.Decimal), ParameterDirection.ReturnValue);
cmd.ExecuteNonQuery(); // an INSERT is always a Non Query
return Convert.ToDecimal(cmd.Parameters["myOutputParameter"].Value);
}
Oracle uses sequences as for his identity columns, if we may say so.
If you have set a sequence for your table primary key, you also have to write a trigger that will insert the Sequence.NextValue or so into your primary key field.
Assuming that you are already familiar with this concept, simply query your sequence, then you will get your answer. What is very practiced in Oracle is to make yourself a function which will return an INT, then within your function, you perform your INSERT. Assuming that you have setup your trigger correctly, you will then be able to return the value of your sequence by querying it.
Here's an instance:
CREATE TABLE my_table (
id_my_table INT PRIMARY KEY
description VARCHAR2(100) NOT NULL
)
CREATE SEQUENCE my_table_seq
MINVALUE 1
MAXVALUE 1000
START WITH 1
INCREMENT BY 2
CACHE 5;
If you want to manage the auto-increment yourself, here's how:
INSERT INTO my_table (
id_my_table,
description
) VALUES (my_table_seq.NEXTVAL, "Some description");
COMMIT;
On the other hand, if you wish not to care about the PRIMARY KEY increment, you may proceed with a trigger.
CREATE OR REPLACE TRIGGER my_table_insert_trg
BEFORE INSERT ON my_table FOR EACH ROW
BEGIN
SELECT my_table_seq.NEXTVAL INTO :NEW.id_my_table FROM DUAL;
END;
Then, when you're inserting, you simply type the INSERT statement as follows:
INSERT INTO my_table (description) VALUES ("Some other description");
COMMIT;
After an INSERT, I guess you'll want to
SELECT my_table_seq.CURRVAL
or something like this to select the actual value of your sequence.
Here are some links to help:
http://www.orafaq.com/wiki/Sequence
http://www.orafaq.com/wiki/AutoNumber_and_Identity_columns
Hope this helps!
You can use below code.
using (OracleCommand cmd = conn.CreateCommand())
{
cmd.CommandText = #"INSERT INTO my_table(name, address)
VALUES ('Girish','Gurgaon India')
RETURNING my_id INTO :my_id_param";
OracleParameter outputParameter = new OracleParameter("my_id_param", OracleDbType.Decimal);
outputParameter.Direction = ParameterDirection.Output;
cmd.Parameters.Add(outputParameter);
cmd.ExecuteNonQuery();
return Convert.ToDecimal(outputParameter.Value);
}
one possible way if one can add one column named "guid" to the table :
when inserting one record from c#, generate a guid and write it to the guid column.
then perform a select with the generated guid, and you have got the id of inserted record :)
Select t.userid_pk From Crm_User_Info T
Where T.Rowid = (select max(t.rowid) from crm_user_info t)
this will return your required id