I am using the following SQL statement to insert new project iterations to the Iterations table...I can insert many iterations at once. The Iterations table has the folllowing fields: {ProjectIteratationID(PK), ProjectID, StartDate, EndDate}
INSERT INTO Iterations (ProjectID, StartDate, EndDate) VALUES (...)
What I also want to do is assign people to the iterations that I am adding, so I need to insert into the ProjectIterationMember table.
"INSERT INTO ProjectIterationMember (ProjectIterationID, MemberID) VALUES ((SELECT ProjectIterationID AS pro_it_id FROM Iterations WHERE ProjectID = '" + proj_id + "'), #member_id)";
I am getting an error. My nested select statement retrieves more than one result.
For example, if I am adding two iterations, the PK 13 and 14 will be generated. I then want to copy the PK to the ProjectIterationMember table and assign a few MemberIDs to those iteration IDs. Thanks for your help!
Use:
INSERT INTO ProjectIterationMember
(ProjectIterationID, MemberID)
SELECT ProjectIterationID AS pro_it_id, #member_id
FROM Iterations
WHERE ProjectID = '" + proj_id + "'
SQL allows you to provide statically assigned values in the SELECT clause.
If you use insert in combination with select you have to omit the values keyword.
Simply use the select after the column list.
Use SCOPE_IDENTITY to get last identity value.
DECLARE #iterationID int;
INSERT INTO Iterations (ProjectID, StartDate, EndDate)
VALUES (#projectID, #startDate, #endDate);
SET #iterationID = SCOPE_IDENTITY();
INSERT INTO ProjectIterationMember (ProjectIterationID, MemberID)
VALUES (#iterationID, #memberID);
Related
I have a stored procedure that inserts a line in a table. This table has an auto incremented int primary key and a datetime2 column named CreationDate. I am calling it in a for loop via my C# code, and the loop is inside a transaction scope.
I run the program twice, first time with a for loop that turned 6 times and second time with a for loop that turned 2 times. When I executed this select on sql server I got a strange result
SELECT TOP 8
RequestId, CreationDate
FROM
PickupRequest
ORDER BY
CreationDate DESC
What I didn't get is the order of insertion: for example the line with Id=58001 has to be inserted after that with Id=58002 but this is not the case. Is that because I put my loop in a transaction scoope? or the precision in the datetime2 is not enough?
It is a question of speed and statement scope as well...
Try this:
--This will create a #numbers table with 1 mio numbers:
DECLARE #numbers TABLE(Nbr BIGINT);
WITH N(N) AS
(SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1)
,MoreN(N) AS
(SELECT 1 FROM N AS N1 CROSS JOIN N AS N2 CROSS JOIN N AS N3 CROSS JOIN N AS N4 CROSS JOIN N AS N5 CROSS JOIN N AS N6)
INSERT INTO #numbers(Nbr)
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM MoreN;
--This is a dummy table for inserts:
CREATE TABLE Dummy(ID INT IDENTITY,CreationDate DATETIME);
--Play around with the value for #Count. You can insert 1 mio rows in one go. Although this runs a while, all will have the same datetime value:
--Use a small number here and below, still the same time value
--Use a big count here and a small below will show a slightly later value for the second insert
DECLARE #Count INT = 1000;
INSERT INTO Dummy (CreationDate)
SELECT GETDATE()
FROM (SELECT TOP(#Count) 1 FROM #numbers) AS X(Y);
--A second insert
SET #Count = 10;
INSERT INTO Dummy (CreationDate)
SELECT GETDATE()
FROM (SELECT TOP(#Count) 1 FROM #numbers) AS X(Y);
SELECT * FROM Dummy;
--Clean up
GO
DROP TABLE Dummy;
You did your insertions pretty fast so the actual CreationDate values inserted in one program run had the same values. In case you're using datetime type, all the insertions may well occur in one millisecond. So ORDER BY CreationDate DESC by itself does not guarantee the select order to be that of insertion.
To get the desired order you need to sort by the RequestId as well:
SELECT TOP 8 RequestId, CreationDate
FROM PickupRequest
ORDER BY CreationDate DESC, RequestId DESC
My requirement is to create multiple tables dynamic
here is part numbers .table number
1. table number 1 has 2 records and table number 2 has also 2 records.
firstly create table no. 1 and fill its records
after that create new second table no. 2 and its records and soo on according to table number
in some case i have only part no. but in this we create another something html in which we display those data which does not have table no.
Declare table variable to store id and tableNo.
declare #TempTable table(id int identity,TableNo int)
Insert into this table of all distinct TableNo column data..
INSERT INTO #TempTable
SELECT DISTINCT TabloNo
FROM TableName
Declare following variable and set its value like...
declare #counter int, #totalTable int, #NoOfTable int, #StrquryInser nvarchar(max)
select #totalTable = count(id) from #TempTable
set #counter = 1
set #StrquryInser = ''
In while block select table data according to tableNo and insert it into #temp1, #temp2...dynamically using this code...
begin
select #NoOfTable = TableNo
from #TempTable
where id = #counter
set #StrquryInser = #StrquryInser + ' select * into #temp' +cast(#counter as varchar(10)) + ' from TableName where isnull([TabloNo],0)='+cast(isnull(#NoOfTable,0) as nvarchar(10))
set #StrquryInser=#StrquryInser + ' select * from #temp' +cast(#counter as varchar(10))
set #counter=#counter+1
end
execute the string Query #StrquryInser like...
exec(#StrquryInser)
In above query you can store your table data in multiple temp variables like temp1, #temp2 etc..
Apart form these #temp table you can also store your data in permanent table using above logic..
I have thought about using distinct but im not too sure how to do it as a single query for efficiency of code, is there a way? I am basically trying to check if there is already an existing data entry, I am trying to check it with BookingTime. Thanks :)
This is my SQL query:
string bookingInfo = "INSERT INTO Booking(BookingDate, BookingTime, CustomerID, EmployeeID, ServiceType, BookingLength) " +
"VALUES (#BookingDate, #BookingTime, #CustomerID, #EmployeeID, #ServiceType, #BookingLength) " +
"where not exists (SELECT 1 FROM Booking WHERE BookingTime = #BookingTime)";
The error I receive: "Additional information: Query input must contain at least one table or query."
The best way is to let the database do the checking.
Create a unique index or constraint on the table:
create unique index unq_booking_bookingtime on booking(bookingtime);
Note: this is based on your query. It seems unlikely to me that only bookingtime defines uniqueness.
The database will then generate an error if it encounters duplicates. You can prevent the error using insert ignore or insert on duplicate key update (the latter is the preferred method).
The WHERE clause is invalid is invalid in the "INSERT ... VALUES" statement shown.
MySQL does provide an "INSERT ... SELECT ..." form of the INSERT statement (which does not use a VALUES clause). The SELECT statement can have a WHERE clause, but to include a WHERE clause in a SELECT, there has to be a FROM clause. You can use an inline view (aka a derived table) to return a single row, or you could use the builtin Oracle-style dummy table DUAL to return a single row. (We don't care what columns get returned, we just need one row returned.)
For example:
INSERT INTO Booking
( BookingDate
, BookingTime
, CustomerID
, EmployeeID
, ServiceType
, BookingLength
)
SELECT #BookingDate
, #BookingTime
, #CustomerID
, #EmployeeID
, #ServiceType
, #BookingLength
FROM ( SELECT 1 ) i
WHERE NOT EXISTS
( SELECT 1
FROM Booking b
WHERE b.BookingTime = #BookingTime
)
Now the SELECT statement (which can be tested separately from the INSERT) will return either zero or one rows. And whatever row it returns will be passed to the INSERT.
As an alternative to the "NOT EXISTS" predicate, you could use an anti-join pattern:
SELECT #BookingDate
, #BookingTime
, #CustomerID
, #EmployeeID
, #ServiceType
, #BookingLength
FROM ( SELECT 1 ) i
LEFT
JOIN Booking b
ON b.BookingTime = #BookingTime
WHERE b.BookingTime IS NULL
string bookingInfo = "INSERT INTO Booking(BookingDate, BookingTime, CustomerID, EmployeeID, ServiceType, BookingLength) " +
"SELECT #BookingDate, #BookingTime, #CustomerID, #EmployeeID, #ServiceType, #BookingLength " +
" FROM Booking WHERE NOT EXISTS (SELECT * FROM Booking WHERE BookingTime = #BookingTime) LIMIT 1 "
Try this SqlFiddle
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
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 */
}