Working with composite primary key in c# - c#

I have a sql table temp.it has 4 columns, 3 of which are primary keys(composite). While doing a insert to a table I need to check if the composite PK exists already in table. If yes I need to update the row else I need to insert a new row to temp table. Can I proceed this way. I don't know hoe to check for PK in table. Kindly guide me. Below is the Insert
string constr = ConfigurationManager.ConnectionStrings["constr"].ToString();
using (OdbcConnection con = new OdbcConnection(constr))
{
try
{
string query = "Insert into temp_table(Name,DeptName,Alias,City) values(name,dept,alias,city)";
con.Open();
OdbcCommand cmd = new OdbcCommand(query, con);
cmd.ExecuteNonQuery();
}
here name, dept and city are composite primary key.

Try to update first, if the record does not exists than the update will fail and then you can do an insert.
This is more efficient because each time the update succeeds then only one statement will be called.
update temp_table
set Alias = #alias
where Name = #name
and DeptName = #dept
if ##rowcount = 0 then
begin
insert into temp_table (Name, DeptName, Alias, City)
values (#name, #dept, #alias, #city)
end

your solution
if not exists (Select * from temp_table where Name=#name and DeptName=#dept and City=#city)
begin
Insert into temp_table
(Name,DeptName,Alias,City)
values(#name,#dept,#alias,#city)
end
else
begin
update temp_table set Alias=#alias where Name=#name and DeptName=#dept and City=#city
end

The Merge Command combine check, insert and update into one command.
Syntax is here:
https://msdn.microsoft.com/en-us/library/bb510625.aspx

Related

Edit existing data in SQL Server database

I have a table SupplierMaster in a SQL Server database with a column SUPPLIERNAME.
I want to edit saved supplier name using stored procedure with below query
ALTER PROCEDURE [dbo].[usp_SupplierMasterUpdateDetails]
(
#SUPPLIERNAME NVARCHAR(50)
)
AS
BEGIN
UPDATE [dbo].[SupplierMaster]
SET [SUPPLIERNAME] = #SUPPLIERNAME
WHERE [SUPPLIERNAME] = #SUPPLIERNAME
END
and I run the BELOW code through "UPDATE BUTTON" to update the data.
string connString = ConfigurationManager.ConnectionStrings["dbx"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connString))
{
using (SqlCommand cmd = new SqlCommand("usp_SupplierMasterUpdateDetails", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// Parameter
cmd.Parameters.AddWithValue("SUPPLIERNAME", AddSupplierTextBox.Text);
// Open Connection
conn.Open();
// ExecuteReader (Select Statement)
// ExecuteScalar (Select Statement)
// ExecuteNonQuery (Insert, Update or Delete)
cmd.ExecuteNonQuery();
MessageBox.Show("SUCCESSFULLY UPDATED", "Successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
But its not updating the selected data.
Please advice and assist me to correct the code for proper work.
You have multiple issues there.
First you need to fix your update query just as Thomas Levesque suggested.
a SQL Server table needs a primary key to be able to uniquely identify a record, for updates for example.
The easiest thing you could do is set that primary key to be identity of type int and make it self generating. Your supplier table could look like this :
SupplierID int, Primary Key, identity
SupplierName nvarchar(100)
Now, when you do an update, you would do it like this:
Update SupplierMaster
Set SupplierName = #supplierName
Where SupplierID = #suplierID
Such a SQL statement will return an int value. This return value will tell you how many SQL rows this update statement has changed. If it says 0 then it means that the SQL statement could not find that id you passed through and nothing changed. If it says 1, then the record was found and updated, if you get more than 1 you have an issue with the SQL statement and multiple rows were updated.
In your code check for this return value and that's how you determine if your update statement was successful or not.

How to insert data into sql server database when the primary key column already set default identity(1, 1)

I'm trying to insert two data columns into my SQL Server database but I get an error at the code line -> cmd.ExecuteNonQuery();
Cannot insert the value NULL into column OrderID, table RestaurantApp.dbo.Junc_Order; column does not allow nulls. INSERT fails.
The OrderID column is actually the primary key in my data table. I set it identity(1, 1) and want to insert other data and meanwhile it can insert 1, 2, 3, 4....automatically.
Here is the part of my code:
string insertString = "INSERT INTO Junc_Order(ID, Quantity)values (#ID, #Quantity)";
SqlCommand cmd = new SqlCommand(insertString, conn);
cmd.Parameters.AddWithValue("#ID", r_ID);
cmd.Parameters.AddWithValue("#Quantity", r_Quantity);
cmd.ExecuteNonQuery();
I already get connection with database ahead of these codes, so the problem should not be that.
Updated Junc_Order table design:
OrderID (PK,FK,int,not null)
ID(FK,int,not null)
Quantity(int,not null)
By viewing your question, it seems that your insert query is not correct:
First of all, you don't need to insert "OrderID" as it is primary key identity so sql server automatically insert it.
second, somewhere you are getting "r_ID" as null that's why you are facing error.Verify it and modify your code with the following:
string insertString = "INSERT INTO Junc_Order(Quantity) values(#Quantity)";
SqlCommand cmd = new SqlCommand(insertString, conn);
cmd.Parameters.AddWithValue("#Quantity", r_Quantity);
cmd.ExecuteNonQuery();

Copying row from 1 table to another in SQL

When a user deletes a row in the database, I want to archive it into a separate table in the database rather than delete it or flag it in the current table. I figure I would need to do something like in this link:
How to copy a row from one SQL Server table to another
The thing is, the archive table has 1 extra column in it that does not match the original table (ArchiveTimeStamp). This ArchiveTimeStamp does not exist in the original table, instead I would use something like
archiveComm.Parameters.AddWithValue("ArchiveTimeStamp", Date.Time.Now);
This is what I have so far:
SqlCommand archiveComm = new SqlCommand("INSERT INTO Archive_Table SELECT * FROM Table WHERE RowID = #rowID", conn);
Is there a way for me to modify the SqlCommand to add another param that doesn't exist in the original Table?
Why not just handle this on the back end? You can create a trigger on the original table to insert into another table after every delete?
Your trigger will look like this:
CREATE TRIGGER onOriginalTableDelete
ON originalTable
FOR DELETE
AS
INSERT INTO anotherTable
SELECT * FROM deleted;
When a record is deleted on the original table, it will insert the deleted record into the other table. You might want to read on using the deleted table here.
Check this SQL Fiddle. Since you're inserting the timestamp in another column, you can just add this on the INSERT INTO SELECT statement:
INSERT INTO OtherTable
SELECT *, CURRENT_TIMESTAMP FROM MainTable;
This could be the query for your trigger:
CREATE TRIGGER onOriginalTableDelete
ON originalTable
FOR DELETE
AS
INSERT INTO anotherTable
SELECT *, CURRENT_TIMESTAMP FROM deleted;
Good question. I'd suggest (as Gian has also suggested) moving the logic you require to backup the deleted row into a trigger that gets fired on delete.
Triggers are events in a database associated to a table which get fired upon an action occurring i.e. insert / update / delete.
So in your scenario, if you create an ON DELETE trigger in the source table, it will get fired when a delete occurs. The SQL contained within the trigger can specify what to do with the deleted data, which in your scenario will be: insert the deleted info into the archive table with a timestamp.
So if you have:
Source_Table:
Col_1
Col_2
Col_3
Archive_Table:
Col_1
Col_2
Col_3
Time_Stamp
You'll need to create a FOR DELETE trigger against Source_Table (something like this):
CREATE TRIGGER SourceDeletedTrigger
ON database.dbo.Source_Table
FOR DELETE
AS
INSERT INTO Archive_Table(Col_1, Col_2, Col_3, Time_Stamp)
SELECT
DELETED.Col_1,
DELETED.Col_2,
DELETED.Col_3,
GETDATE()
FROM DELETED
GO
The above is some rough SQL which may contain a couple of syntax errors but the guts of the idea is conveyed.
You will have to use to explicit column list and values form of the INSERT statement:
INSERT INTO Archive_Table (
Col1
,Col2
,Col3 )
SELECT
Col1
,Col2
,Col3
FROM
Table
WHERE
Row_ID = #Row_ID
See Insert into ... values ( SELECT ... FROM ... )
I think you have to specify the columns with something like this
INSERT INTO tab1
(col1, col2)
SELECT col1, col2
FROM tab2
WHERE RowID = #rowID"
You need to specify the columns name in that case:
archiveComm.Parameters.AddWithValue("ArchiveTimeStamp", Date.Time.Now);
string SQL = "INSERT INTO Archive_Table (Col1,Col2,ArchiveTimeStamp) " & _
"SELECT Col1,Col2,#ArchiveTimeStamp FROM Table WHERE RowID = #rowID"
SqlCommand archiveComm = new SqlCommand(SQL, conn);
Here is my suggestion, you are forced to supply the column names or it won't let you run the query, however I understand you would prefer a generic solution that worked for any table so I suggest building the insert SQL dynamically, cache it on your application, and then just execute it with your extra archive column. Here is a c# example:
public class ArchiveTableRow
{
private static readonly IDictionary<string, string> _cachedInsertStatements = new Dictionary<string, string>();
public void Archive(string tableName, string rowId)
{
if (_cachedInsertStatements.ContainsKey(tableName) == false)
{
BuildInsertStatement(tableName);
}
var insertQuery = _cachedInsertStatements[tableName];
// ...
SqlCommand archiveComm = new SqlCommand(insertQuery, conn);
// ...
archiveComm.Parameters.AddWithValue("ArchiveTimeStamp", Date.Time.Now);
// ...
}
private void BuildInsertStatement(string tableName)
{
// Get the columns names:
var getColumnNamesQuery = #"
SELECT Table_Schema, Column_Name
FROM Information_Schema.Columns
WHERE Table_Name = '" + tableName + "'
Order By Ordinal_Position";
// Execute the query
SqlCommand archiveComm = new SqlCommand(getColumnNamesQuery, conn);
// Loop and build query and add your archive in the end
// Add to dictionary
}
}
You would use it with something like:
var archiveRow = new ArchiveTableRow();
archiveRow.Archive("TableName", rowId);

how can i update SQL table logic

I have a table structured as,
Table 3
Fruit ID - Foreign Key (Primary Key of Table 1)
Crate ID - Foreign Key (Primary Key of Table 2)
Now I need to execute a query which will,
Update Crate ID of Fruit ID if Fruit ID is already in Table, and if not then insert record in table 3 as new record.
This is what I got in code right now,
private void RelateFuirtWithCrates(List<string> selectedFruitIDs, int selectedCrateID)
{
string insertStatement = "INSERT INTO Fruit_Crate(FruitID, CrateID) Values " +
"(#FruitID, #CrateID);"; ?? I don't think if it's right query
using (SqlConnection connection = new SqlConnection(ConnectionString()))
using (SqlCommand cmd = new SqlCommand(insertStatement, connection))
{
connection.Open();
cmd.Parameters.Add(new SqlParameter("#FruitID", ????? Not sure what goes in here));
cmd.Parameters.Add(new SqlParameter("#CrateID",selectedCrateID));
}
You can do an "upsert" with the MERGE syntax in SQL Server:
MERGE [SomeTable] AS target
USING (SELECT #FruitID, #CrateID) AS source (FruitID, CrateID)
ON (target.FruitID = source.FruitID)
WHEN MATCHED THEN
UPDATE SET CrateID = source.CrateID
WHEN NOT MATCHED THEN
INSERT (FruitID, CrateID)
VALUES (source.FruitID, source.CrateID);
Otherwise, you can use something like:
update [SomeTable] set CrateID = #CrateID where FruitID = #FruitID
if ##rowcount = 0
insert [SomeTable] (FruitID, CrateID) values (#FruitID, #CrateID)

Inserting data into one table then multiple rows into another using data from the first using stored procedures (SQL + C#)

Ok so I am new here :) I am relatively new to SQL, and I am trying to insert data into multiple tables. I have both inserts to work however I want it so if one fails neither are committed.
The tables look like this:
Student -
StudentID - int PK,
StudentName - Varchar,
etc ...
Class -
ClassID - int PK,
ClassName - varchar,
etc...
StudentClass -
StudentID,
ClassID,
What I am trying to do is create a new Student whom can belong to multiple classes. So I have created the Student class table to break up the many-many relationship. I have a stored procedure to insert a new student and return the newest StudentID and then I use this StudentID, in a new stored procedure, and a table value parameter to insert multiple rows into StudentClass table. These are the stored procedures:
Create A Student:
#FirstName varchar(20) = '',
#LastName varchar(20) = '',
#PredictedGrade char(1) = '',
#ActionPlan bit = 0,
#StudentActive bit = 1,
#StudentID int out
INSERT INTO Student (FirstName, LastName, PredictedGrade, ActionPlan, StudentActive)
VALUES (#FirstName, #LastName, #PredictedGrade, #ActionPlan, #StudentActive)
SET #StudentID = SCOPE_IDENTITY()
Add Multiple Rows To StudentClass Table:
(#StudentClassCollection As InsertStudentClass READONLY)
INSERT INTO StudentClass(StudentID, ClassID)
SELECT StudentID, ClassID FROM #StudentClassCollection
So both of these work however I don't know how to make it so if one fails the other will not execute and changes will not be committed? So effectively I need to perform both actions one after the other in the same stored procedure? I think! As I said I am new so if I have done anything wrong please let me know I will correct it :)
In case of an error, rollback will be issued automatically
SET XACT_ABORT ON
begin transaction
-- YOUR WORK HERE
commit transaction
try like the below
using (SqlConnection connection= new SqlConnection(connectionstring))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
try
{
SqlCommand command = new SqlCommand("proc1",connection);
//execute the above command
command.CommandText="proc2";
//execute command again for proc2
transaction.Commit();
}
catch
{
//Roll back the transaction.
transaction.Rollback();
}
}
begin tran
// all insert , update script here
IF ##ERROR <> 0
BEGIN
ROLLBACK tran
END
ELSE
commit tran

Categories