Reputation: 1054
Currently i'm using the following C# code to insert rows into a database
int result = 0;
using (SqlConnection connect = new SqlConnection(connectionString))
{
string insertQuery = @"Insert Into Conversions (CID, Source, Destination, Packages, CreatedBy, SourceID)
SELECT @CID, @Source, @Destination, @Packages, @CreatedBy, @SourceID";
SqlCommand command = new SqlCommand(insertQuery, connect);
command.Parameters.AddWithValue("CID", cidBox.Text);
command.Parameters.AddWithValue("Source", sourceSoftwareBox.Text);
command.Parameters.AddWithValue("Destination", destinationSoftwareBox.Text);
command.Parameters.AddWithValue("Packages", packagesBox.Text);
command.Parameters.AddWithValue("CreatedBy", Environment.UserName);
command.Parameters.AddWithValue("SourceID", sourceID.sourceID);
connect.Open();
result = Convert.ToInt32(command.ExecuteScalar());
}
I have another table called HistoricalData
with the following columns:
Id
, Status
, Comments
, Date
I want to be able to Insert into the Conversions
table, select the Id
that was just auto created from the insert and use that Id
in a second insert into the HistoricalData
table. Can I do this with some sort of SQL magic?
Upvotes: 0
Views: 274
Reputation: 69749
You can use the OUTPUT
clause to insert directly into the 2nd table. Your SQL would be something like:
INSERT Conversions (CID, Source, Destination, Packages, CreatedBy, SourceID)
OUTPUT inserted.ID, @Status, @Comments, GETDATE()
INTO HistoricalData (ID, Status, Comments, Date)
VALUES (@CID, @Source, @Destination, @Packages, @CreatedBy, @SourceID);
This won't work however if there is a foreign key relationship between the two tables. In some cases I would advise simply using the output clause to insert into a temp table before inserting to the child table, but since you are only inserting a single row and only accessing the identity field, you could just use SCOPE_IDENTITY()
:
INSERT Conversions (CID, Source, Destination, Packages, CreatedBy, SourceID)
VALUES (@CID, @Source, @Destination, @Packages, @CreatedBy, @SourceID);
INSERT HistoricalData (ID, Status, Comments, Date)
VALUES (SCOPE_IDENTITY(), @Status, @Comments, GETDATE());
N.B. In both instances I was unsure of what you would want to add as Status
, Comment
, and Date
, so have used variables and GETDATE()
, you may need to adjust this.
Another note, I have switched from a SELECT
with no FROM
to the VALUES
constructor for the insert, mostly out of second nature when rewriting the queries. There is no difference in the two methods, although I do find using VALUES
displays intent better, it shows clearly nothing is being selected.
Upvotes: 1
Reputation: 406
If your database in question supports stored procedures i would definitely go that way. Create a stored procedure with required parameters. Create your SqlCommand like this:
SqlCommand command = new SqlCommand("MyStoredProcedureName", connect);
command.CommandType=CommandType.StoredProcedure;
Pass your parameters like in your current code. Your database stored procedure would look something like this:
CREATE PROCEDURE MyStoredProcedureName
@CID bigint,
..... all params
AS
BEGIN
DECLARE @myNewID bigint
SET NOCOUNT ON;
Insert Into Conversions (CID, Source, Destination, Packages, CreatedBy, SourceID) VALUES (@CID, @Source, @Destination, @Packages, @CreatedBy, @SourceID)
SET @myNewID=SCOPE_IDENTITY()
-- Now you can insert what you want where you want
INSERT INTO HistoricalData (Column list...) (Values list ... @myNewID)
END
If you are not using Entity Framework or something like this it is best to keep database code separate from rest of your code. So when you change table names/column names or any change in database structure you don't have to change your code. Just change the database part and your stored procedures.
Upvotes: 1