Uupdate values in two tables via stored procedure - c#

I have two tables and I need to update values in them via a stored procedure. Tried too much to update but some times it update the first table only, others the second or even fail due to cannot allow duplicates. Also when it updates the WHOLE data in the table becomes the same as the new updated ones. I've now reached to this error after all these lines of codes
Cannot insert the value NULL into column 'Emp_ID',table 'DatePics'; column does not allow nulls. UPDATE fails.The statement has been terminated
Here is the SQL code :
ALTER procedure [dbo].[UpdateEmp]
#EmpName nvarchar(100),
#Nationality nvarchar(30),
#Passport nvarchar(20),
#ContractDate date,
#HealthDate date
AS
BEGIN
set nocount on;
DECLARE #IDs table (ID int )
UPDATE Employee SET
EmpName=#EmpName, Nationality=#Nationality, Visa=#Visa, Passport=#Passport,
ReceivedDate=#ReceivedDate,IDIssue=#IDIssue, IDExpiry=#IDExpiry, Sponsor=#Sponsor
output inserted.ID into #IDs (ID)
WHERE ID = #ID
UPDATE DatePics SET
FingerDate=#FingerDate, ContractDate=#ContractDate, HealthDate=#HealthDate
where Emp_ID in (select ID from #IDs);
END
After writing the stored procedure code, I wrote the C# code like this:
private void updatebtn_Click(object sender, EventArgs e)
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = db.con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "UpdateEmp";
cmd.Parameters.AddWithValue("#EmpName", NameSeartxt.Text);
cmd.Parameters.AddWithValue("#Nationality", NatSeartxt.Text);
cmd.Parameters.AddWithValue("#Passport", PassSeartxt.Text);
cmd.Parameters.AddWithValue("#ContractDate", ContractSeartxt.Text);
cmd.Parameters.AddWithValue("#HealthDate", HealthSeartxt.Text);
db.con.Open();
int up = cmd.ExecuteNonQuery();
if (up > 0)
{
MessageBox.Show("Update done ", "DONE !");
SearNametxt.Text = "";
}
else
{
MessageBox.Show("Failed to update", "FAIL !");
SearNametxt.Text = "";
}
db.con.Close();
}
Any clue?

I can see three problems with your query. 1 You declare ID, but don't assign it before using it, so it will always be NULL for the first query, so this will never update any rows:
DECLARE #ID int
UPDATE FrstTable SET
EmpName=#EmpName, Nationality=#Nationality, Passport=#Passport
WHERE ID = #ID
Secondly, you are using SCOPE_IDENTITY to attempt to get the ID of the record that has been updated. You can't do that, SCOPE_IDENTITY will return the last inserted ID, it is not affected by updates. You will need to use OUTPUT to get the Updated ID:
DECLARE #IDs TABLE (ID INT);
UPDATE FirstTable
OUTPUT inserted.ID INTO #Ids (ID)
SET EmpName = #EmpName,
Nationality = #Nationality,
Passport = #Passport;
Thirdly, your second update statement has no where clause, so will update the entire table:
UPDATE ScndTable
SET Emp_ID=#ID, ContractDate=#ContractDate, HealthDate=#HealthDate
WHERE EmpID IN (SELECT ID FROM #Ids);

Your stored procedure looks weird to me. I believe there should be a WHERE cluase for the second UPDATE otherwise it will always update the whole ScndTable table. set #ID = SCOPE_IDENTITY(); seems to be reduntant here. Are you trying to perform insert into ScndTable if there's no corresponding Emp_ID there? Finnaly explicitly create a transaction to update either both tables or none.
Hope it helps!

Please assign the value of #ID variable, before executing the first update statement.
I think you are trying to update some row, so you can pass the 'id' value from the CSHARP code. When you use the SCOPE_IDENTITY, you will get the last inserted value. Try to pass the ID value from the front end.

Related

Creating method on how to have Selecting MAX Function in C# with SQL

I have this kind of method on inserting data
private void InsertReceipt()
{
decimal Stub;
Stub = Math.Floor(decimal.Parse(txtAmount.Text) / 2000);
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO Ticket(CustomerID, Date, Store, Amount, NoStub)" +
"VALUES (#CustomerID, #Date, #Store, #Amount, #NoStub) ";
cmd.Parameters.AddWithValue("#CustomerID", txtCustomerID.Text);
cmd.Parameters.AddWithValue("#Date", dtpDate.Value.Date.ToString());
cmd.Parameters.AddWithValue("#Store", txtStore.Text);
decimal amount = decimal.Parse(txtAmount.Text);
cmd.Parameters.AddWithValue("#Amount", amount);
cmd.Parameters.Add("#NoStub", SqlDbType.Decimal).Value = Stub;
cmd.ExecuteNonQuery();
}
I just want to have a method that if you insert a data in table "Ticket" there's another table will be updating.
CustomerID Date Store Amount NoStub
1 6/7/2013 Nike 4000 2
2 6/7/2013 Adidas 6000 3
This table will be updating, for example I will be using table named "StubRange", This output will be generate.
RangeID CustomerID NoStub TickerStart TickerEnd
1 1 2 00001 00002
2 2 3 00003 00005
I just want to learned how to have this kind of kind of method.
What you are looking for is an After Insert trigger.
Basically you can think of it as an event that triggers after an insert takes place (hence trigger...).
Your trigger should look something like:
CREATE TRIGGER YourTriggerName --The name of your trigger
ON Ticket --The table it will be observing
AFTER INSERT,UPDATE --It will trigger after insert / update
AS
--The actions you want to do. For example:
DECLARE #CustomerId int
SET #CustomerId = (SELECT CustomerId FROM inserted) --you might want to use 'inserted' table
--Inset values
Insert into StubRange (CustomerID , NoStub)
Select Distinct ins.CustomerID, ins.NoStub
From Inserted ins
--Update existing records
UPDATE StubRange
set --Set what ever it is you want to update
WHERE CustomerId = #CustomerId
More about Inserted table - According to Microsoft:
The inserted table stores copies of the affected rows during INSERT
and UPDATE statements. During an insert or update transaction, new
rows are added to both the inserted table and the trigger table. The
rows in the inserted table are copies of the new rows in the trigger
table.
Well you need to write a insert trigger when ever you insert record in Ticket table. You can refer below syntax to create trigger. This is a Oracle syntax
CREATE OR REPLACE TRIGGER TRIGGER_INSERT_STUBRANGE
AFTER INSERT ON TICKET
FOR EACH ROW
DECLARE
raise_exception Exception;
BEGIN
--WRITE YOUR INSERT STATEMENT HERE
Exception
when raise_exception then
RAISE_APPLICATION_ERROR(-20001, sqlerrm );
END;
This will create an insert trigger on your table1 on updating table1 , table2 will b updated with CustomerID, NoStub from table 1 and rest of properties depends on your business logic
CREATE TRIGGER trig_Update_table
ON [tableName1]
FOR INSERT
AS
Begin
Insert into tableName2 (CustomerID , NoStub)
Select Distinct i.CustomerID, i.NoStub
from Inserted i
End

Inserting AutoIncrementID into DB

Hi i'm having trouble with inserting incremented userid inside my db below is my table,stored proc,and my code.
CREATE TABLE [dbo].[Assignment2]
(
userID int PRIMARY KEY IDENTITY(1,1),
Name varchar(255) NOT NULL,
Age int NOT NULL,
Hobbies varchar(255)
)
and a stored procedure
ALTER PROCEDURE [db].[p_Assignment2_ins]
#userID int,
#Name nvarchar(100),
#Age int,
#Hobbies nvarchar(100)
AS
INSERT INTO [DB].[db].[Assignment2]
([Name]
,[Age]
,[Hobbies])
VALUES
(#Name
,#Age
,#Hobbies)
If ##Error <> 0
Return -1
Select #userID = ##Identity // this one just get the latest id that we inserted right?
Return 0
I have some question :
I want to know how do we insert the UserID from the code behind because If the table is empty at first shouldn't we insert a data first into the table
How do we generate an AutoIncrementID from codebehind and insert it
SqlConnection conn = new SqlConnection(ts.ConnMethod());
SqlCommand cmd = new SqlCommand("p_Assignment2_ins", conn);
cmd.CommandType = CommandType.StoredProcedure;
//I'm missing how we should add the IncrementedID
cmd.Parameters.AddWithValue("#Name", TextBox1.Text);
cmd.Parameters.AddWithValue("#Age", TextBox2.Text);
cmd.Parameters.AddWithValue("#Hobbies", TextBox3.Text);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
Any help is really appreciated thanks
Select #userID = ##Identity // this one just get the latest id that we inserted right?
No, you should use SCOPE_IDENTITY(). ##Identity returns the last id, yes, but not the last id from your insert. If you have a trigger, for example, that also produces an insert on a another table as a result of your insert, you will get the id inserted on the other table by that trigger.
Here's a nice article explaining the differences.
As far as inserting autoincrement values on your table; you can't do this unless you disable the constraint first but in essence, this shouldn't be necessary unless you are doing some sort of data import. In your scenario, you should be able to just insert values on the other columns except the identity field with autoincrement. The database will take care of inserting the appropriate value for you.
If you have AUTOINCREMENT field, you SHOULD NOT insert and generate values at all. DB is doing all by itself. So, remove the code that inserts ID-s

Updating data with same primary key

I am reading data from csv file and adding data in database. At time of inserting data into database I want to update data with same primary key.
e.g.) I am using two Columns Bar-codes (PK) and Quantity. So, when I insert data from csv file similar barcode quantity will get added.
Can anyone help me? I am using C#.NET and SQL.
Thanks,
Rushabh Shah.
check out the merge keyword. it should do pretty much waht you're asking for.
here's a stored proc that should do it for you.
CREATE PROCEDURE dbo.InsertBarcodeData
#Barcode varchar(255),
#Quantity int
AS
BEGIN
SET NOCOUNT ON;
MERGE myTableName AS target
USING (SELECT #Barcode, #Quantity) AS source (BarCode, Quantity)
ON (target.Barcode= source.Barcode)
WHEN MATCHED THEN
UPDATE SET Quantity = source.Quantity + target.Quantity
WHEN NOT MATCHED THEN
INSERT (BarCode, Quantity)
VALUES (source.BarCode, source.Quantity)
END;
GO
create procedure InsertOrUpdateSales
(
#bar_code nvarchar(100),
#quantity int
)
as
if exists (select * from sales where bar_code = #bar_code)
update sales set quantity = quantity + #quantity where bar_code = #bar_code
else
insert into sales ( bar_code, quantity) values ( #bar_code, #quantity )
go
And
public static void InsertOrUpdateSales(string connection, string barCode, int quantity)
{
using(SqlConnection conn = new SqlConnection(connection))
{
using(SqlCommand comm = new SqlCommand("InsertOrUpdateSales", conn))
{
comm.CommandType = CommandType.StoredProcedure;
comm.Paramters.AddWithValue("#bar_code", barCode);
comm.Paramters.AddWithValue("#quantity", quantity);
comm.ExecuteNonQuery();
}
}
}
Alternatively, if you want to use the merge statement (as #Chris Lively and #nathan gonzalez mentioned) you could get really fancy and do it like this:
BULK INSERT the data from the CSV file to an empty temp table.
MERGE the temp table with the existing table.
TRUNCATE the temp table.
This might give you the best results. (For certain values of "best".)
If you can assume that there is already an existing entry for all of the bar codes in the table you could do this with a Stored procedure with two incominig parameters (#BarCodeID and #AdditionalQuantity)
UPDATE yourTable SET Quantity = Quantity + #AdditionalQuantity WHERE BarCode = #BarCodeID
You can add a Trigger to the table. When ever something is inserted in the table, you can have it run a stored procedure.

C#/SQL get autoincremented field value

I have a table with autoincremented primary key. In my code I am trying to receive the new autoincremented value when I execute each 'insert' query. Is there a way to do it programatically?
Thanks.
UPD:
Assume I have a table:
TABLE User ( userID INT NOT NULL AUTO_INCREMENT, name VARCHAR( 25 ) NOT NULL , email VARCHAR( 50 ) NOT NULL , UNIQUE ( userID ) );
And I when I insert new values (name and email) to this table I want automatically receive newly generated userID. Ideally I am looking for any ways to do that with a single transaction and without stored procedures.
Have your sql/stored proc return scope_identity() or if you are using Linq2SQL or EF the entity used for insertion gets the new id.
In the stored proc it is:
ALTER proc [dbo].[SaveBuild](
#ID int = 0 output,
#Name varchar(150)=null,
#StageID int,
#Status char(1)=null
)
as
SET NOCOUNT ON
Insert into Builds
(name, StageID, status)
values (#Name, #StageID, #Status)
select #ID = scope_identity()
RETURN #ID
In the C# code you have:
public int SaveBuild(ref int id, ref string Name)
{
SqlCommand cmd = GetNewCmd("dbo.SaveBuild");
cmd.Parameters.Add("#ID", SqlDbType.Int).Value = id;
cmd.Parameters["#ID"].Direction = ParameterDirection.InputOutput;
cmd.Parameters.Add("#Name", SqlDbType.VarChar).Value = Name;
cmd.Parameters.Add("#StageID", SqlDbType.Int).Value = 0;
ExecuteNonQuery(cmd);
id = (int)cmd.Parameters["#ID"].Value;
return id;
}
Dependent upon your situation, you might be better off using table-valued parameters to pass your inserts to a stored procedure, then use OUTPUT INSERTED to return a table-valued parameter from your stored procedure.
It will drastically reduce the number of hits required if you're processing multiple items.
Are you limited to building SQL on the client and sending it to the server? Cause if you can use a stored procedure, this is easy to do. In the stored proc, do the insert and then, either
Select Scope_Identity() as the last statement in the stored proc., or
Use a output parameter to the stored proc, (say named #NewPKValue) and make the last statement:
Set #NewPKValue = Scope_Identity()
Otherwise, you need to send a batch of commands to the server that include two statements, the insert, and Select Scope_Identity() and execute the batch as though it was a select statement
You could use the SQL statement SELECT scope_identity().

Getting autonumber primary key from MS SQL Server

I am currently working in C#, and I need to insert a new record into one table, get the new primary key value, and then use that as a foreign key reference in inserting several more records. The Database is MS SQL Server 2003. All help is appreciated!
The way to get the identity of the inserted row is with the SCOPE_IDENTITY() function. If you're using stored procedures then this would look something like the following to return the row identity as an output parameter.
CREATE PROCEDURE dbo.MyProcedure
(
#RowId INT = NULL OUTPUT
)
AS
INSERT INTO MyTable
(
Column1
,Column2
,...
)
VALUES
(
#Param1
,#Param2
,...
);
SET #RowId = SCOPE_IDENTITY();
You can then use this value for any subsequent inserts (alternatively, if you can pass the data all into the stored procedure, then you can use it in the remainder of the procedure body).
If you're passing the SQL in dynamically then you use much the same technique, but with a single string with statement delimiters (also ; in SQL), e.g.:
var sql = "INSERT INTO MyTable (Column1, Column2, ...) VALUES (#P1, #P2, ...);" +
"SELECT SCOPE_IDENTITY();";
Then if you execute this using ExecuteScalar you'll be able to get the identity back as the scalar result and cast it to the right type. Alternatively you could build up the whole batch in one go, e.g.
var sql = "DECLARE #RowId INT;" +
"INSERT INTO MyTable (Column1, Column2, ...) VALUES (#P1, #P2, ...);" +
"SET #RowId = SCOPE_IDENTITY();" +
"INSERT INTO MyOtherTable (Column1, ...) VALUES (#P3, #P4, ...);";
This may not be exactly the right syntax, and you may need to use SET NOCOUNT ON; at the start (my mind is rusty as I rarely use dynamic SQL) but it should get you on the right track.
The best way of doing this is the use SCOPE_IDENTITY() function in TSQL. This should be executed as part of the insert i.e.
SqlCommand cmd = new SqlCommand(#"
INSERT INTO T (Name) VALUES(#Name)
SELECT SCOPE_IDENTITY() As TheId", conn);
cmd.AddParameter("#Name", SqlDbType.VarChar, 50).Value = "Test";
int tId = (int)cmd.ExecuteScalar();
Alternatively you can assign SCOPE_IDENTITY() to a variable to be used in successive statements. e.g.
DECLARE #T1 int
INSERT INTO T (Name) VALUES('Test')
SELECT #T1 = SCOPE_IDENTITY()
INSERT INTO T2 (Name, TId) VALUES('Test', #T1)
If you are just using SQL then check Duncan's answer. If however you are using LINQ then you can create the entity, save it to the DB and the ID parameter will be populated automatically.
Given a user entity and a user table it might look like this:
using(var db = new DataContext()) {
var user = new User { Name = "Jhon" };
db.Users.InsertOnSubmit(user);
db.SubmitChanges();
/* At this point the user.ID field will have the primary key from the database */
}

Categories

Resources