I am writing a store procedure in T-SQL which inserts a row to the table, based on parameters
#UserName ,#CompanyName ,#RestName,#Desc
INSERT INTO Orders(UserId,CompanyId,RestId)
SELECT UserNames.Id,CompanyNames.Id,RestNames.Id FROM UserNames,CompanyNames,RestNames
WHERE
UserNames.Name = #UserName AND
CompanyNames.Name = #CompanyName AND
RestNames.Name = #RestName
Besides the insert to the 3 columns above,I also want to insert the #Desc value.
I tried :
INSERT INTO Orders(UserId,CompanyId,RestId,Desc)
VALUES(
(SELECT UserNames.Id,CompanyNames.Id,RestNames.Id FROM UserNames,CompanyNames,RestNames
WHERE
UserNames.Name = #UserName AND
CompanyNames.Name = #CompanyName AND
RestNames.Name = #RestName),#Desc)
Only one expression can be specified in the select list when the subquery is not introduced with EXISTSt-
It doesn`t work giving the following error:
#UserName ,#CompanyName ,#RestName,#Desc
INSERT INTO Orders(UserId,CompanyId,RestId, Desc_Column)
SELECT UserNames.Id,CompanyNames.Id,RestNames.Id , #Desc --<-- Just SELECT that variable
FROM UserNames,CompanyNames,RestNames -- in your select statement.
WHERE UserNames.Name = #UserName
AND CompanyNames.Name = #CompanyName
AND RestNames.Name = #RestName
Retrieve ID Values Inserted
DECLARE #t TABLE (ID INT); --<-- Declare a table variable
INSERT INTO Orders(UserId,CompanyId,RestId, Desc_Column)
OUTPUT Inserted.ID INTO #t --<-- use OUTPUT, get values from INSERTED Table
SELECT UserNames.Id,CompanyNames.Id,RestNames.Id , #Desc --and insert them into your table variable
FROM UserNames,CompanyNames,RestNames
WHERE UserNames.Name = #UserName
AND CompanyNames.Name = #CompanyName
AND RestNames.Name = #RestName
/*At last just simply select from that table variable to get the inserted IDs*/
SELECT * FROM #t
Related
I have two tables; the first named PAYMENT and the second is a historical table named RecordPay.
I have two triggers, the first one is for insert in order to insert into the historical tables records from Payment table.
Here is the code:
ALTER TRIGGER [dbo].[INSERT_HIST]
ON [dbo].[PAYMENT]
FOR INSERT
AS
BEGIN
DECLARE #User_op varchar(50)
DECLARE #RGNO varchar(50)
DECLARE #PAYEUR varchar(50)
DECLARE #DATESYS SMALLDATETIME
DECLARE #RG_DATE SMALLDATETIME
DECLARE #RG_Montant varchar(50)
SELECT #User_op = cbUserName
FROM cbUserSession
WHERE cbSession = ##SPID
SELECT #PAYEUR = CT_NumPayeur FROM INSERTED
SELECT #DATESYS = GETDATE()
SELECT #RG_Montant = RG_Montant FROM INSERTED
SELECT #RG_DATE = RG_DATE FROM INSERTED
SELECT #RGNO = RG_No FROM INSERTED
INSERT INTO RecordPay (RG_NO, PAYEUR, CAISSIER, Montant, DATESYS, DATECAI)
VALUES (#RGNO, #PAYEUR, #user_op, #RG_Montant, #DATESYS, #RG_DATE)
This works well, my problem when I delete a row from PAYMENT, in RecordPay the record exists, and then when I insert another row in PAYMENT I had two RG_NO whith the same number.
For example I insert a row in PAYMENT with RG_NO=1 then I deleted, and I create another row with RG_NO=2, in the recordPay (historical table) i get two lines with RG_NO=1.
Here is the trigger for delete but it does not work
ALTER TRIGGER [dbo].[DEL_HIST]
ON [dbo].[PAYMENT]
AFTER DELETE
AS
BEGIN
DECLARE #User_op varchar(50)
DECLARE #RGNO varchar(50)
DECLARE #PAYEUR varchar(50)
DECLARE #DATESYS SMALLDATETIME
DECLARE #RG_DATE SMALLDATETIME
DECLARE #RG_Montant varchar(50)
SELECT #PAYEUR = CT_NumPayeur FROM DELETED
SELECT #RG_Montant = RG_Montant FROM DELETED
SELECT #RG_DATE = RG_DATE FROM DELETED
SELECT #RGNO = RG_No FROM DELETED
DELETE FROM RECORDPAY WHERE
RG_NO=#RGNO and PAYEUR= #PAYEUR and CAISSIER=#user_op and Montant=#RG_Montant
END
Your trigger will BREAK as soon as an INSERT statement inserts more than 1 row at a time - because in that case, your trigger gets called once for the INSERT statement, and Inserted will contain multiple rows.
Which one of those 10 rows are you selecting from here??
SELECT #PAYEUR = CT_NumPayeur FROM INSERTED
SELECT #RG_Montant = RG_Montant FROM INSERTED
SELECT #RG_DATE = RG_DATE FROM INSERTED
SELECT #RGNO = RG_No FROM INSERTED
It's arbitrary and non-deterministic - and you will simply ignore all other rows in Inserted.
You need to rewrite your trigger to take this into account:
ALTER TRIGGER [dbo].[INSERT_HIST]
ON [dbo].[PAYMENT]
FOR INSERT
AS
BEGIN
DECLARE #User_op varchar(50)
SELECT #User_op = cbUserName
FROM cbUserSession
WHERE cbSession = ##SPID
-- insert a record for ALL the rows that were inserted into
-- your history table in a single, elegant, set-based statement
INSERT INTO RecordPay (RG_NO, PAYEUR, CAISSIER, Montant, DATESYS, DATECAI)
SELECT
RG_No, CT_NumPayeur, #User_op, RG_Montant, SYSDATETIME(), RG_Date
FROM
Inserted
I try to create a Trigger that will insert a Unique ID in a table and then get the created ID and use it on the table that "Triggered the trigger"
So I insert some data in my table and then I want the trigger to insert some data in another table (master ID table), it then needs to get the just created ID (auto increment INT) and add this ID to the table ID that the trigger fired on.
I tried quite some different options but it just does not insert the ID and it will give me an error.
Hope you can help me out.
CREATE TRIGGER [dbo].[TROidMemoDiaryHeader]
ON [dbo].[InvoiceDiaryHeader]
FOR INSERT
AS
DECLARE #TEMP uniqueidentifier, #Lock INT, #Object INT, #User V ARCHAR(MAX), #Delay NCHAR(12), #ID INT
SET #TEMP = NEWID()
SET #Lock = '0' --staat geen wijziging meer toe
SET #Object = '5' -- aanduiding bron
SET #User = CURRENT_USER
--SET #Delay = '00:00:00:125' -- Wacht voor een kwart seconde voor verder te gaan
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
--SET NOCOUNT ON;
INSERT INTO [dbo].[AbstractMBOBase] ([Uid], [OptimisticLockField], [ObjectType], [User])
SELECT #TEMP, #Lock, #Object, #User
IF EXISTS (SELECT [Uid] FROM [dbo].AbstractMBOBase WHERE [Uid] = #TEMP)
BEGIN
INSERT INTO [InvoiceDiaryHeader](Oid)
SELECT Oid FROM inserted
/*
SELECT * INTO #tmpOID FROM AbstractMBOBase WHERE [Uid] = #TEMP
UPDATE [dbo].InvoiceDiaryHeader SET Oid = (SELECT a.[Oid] FROM [dbo].[AbstractMBOBase] AS a
WHERE [Uid] = #TEMP)
--CREATE TABLE [dbo].#TempOID()
--SELECT * INTO #TempOID FROM INSERTED
*/
/*
--UPDATE [MemoDiaryHeader]
SET #ID = (SELECT a.[Oid] FROM [dbo].[AbstractMBOBase] AS a
WHERE [Uid] = #TEMP)
INSERT INTO [MemoDiaryHeader]([Oid])
SELECT #ID
--FROM inserted
--select [Oid]=i.[Oid] from inserted i
*/
END
--END
END
GO
I am trying to perform the following using a MERGE statement
I have a table that has two columns (TagId is an Identity (PK) and Name as a VARCHAR). I would like to check first if Name exists before I insert it. If it does exist, I would like to get the Identity value. Otherwise, I would insert it and pick up the inserted value.
The beauty of MERGE is it is transactional in nature. so, I won't have to worry about getting an UNIQUE index violation due to timing. Any suggestions? I prefer not to use transactions.
DECLARE
#TagId INT,
#Name VARCHAR(100) = 'TagName'
SELECT TOP(1)
#TagId = T.TagId
FROM dbo.Tag AS T
WHERE T.Name = #Name
IF #TagId IS NULL
BEGIN
INSERT dbo.Tag (Name) VALUES (#Name)
SELECT #TagId = SCOPE_IDENTITY()
END
After trying, this seems to work: it doesn't seem right. The MATCHED clause is required. Otherwise, #Table won't have value.
DECLARE #Table TABLE
(
TagId INT,
Name VARCHAR(100)
)
DECLARE
#TagId INT,
#Name VARCHAR(100) = 'TdagNamed122'
MERGE dbo.Tag AS Target
USING(SELECT #Name) AS Source (Name)
ON Source.Name = Target.Name
WHEN MATCHED THEN
UPDATE SET #TagId = Target.TagId
WHEN NOT MATCHED THEN
INSERT (Name) VALUES (Source.Name)
OUTPUT INSERTED.* INTO #Table
;
SELECT * FROM #Table
Yes as per the documentation , it should execute all statements in atomic fashion
I didn't face any concurrency issues
But There are some concerns as per the link
http://www.mssqltips.com/sqlservertip/3074/use-cauti
I have two stored procedures as follows:
create stored procedure p1
as
select * from table1 where datediff(day, table1.[date], getdate())
create stored procedure p2
as
declare #t1 table(
ref varchar(20)
)
insert into #t1 select * from table1 where ref = 'some ref'
declare #t2 table(
fname varchar(20),
lname varchar(20),
email varchar(1000)
)
declare #len int = (select count(ref) from #t1)
while #len > 0
begin
declare #value varchar(20) = (select top 1 ref from #t1)
insert into #t2 select * from table2 where ref = #ref
delete from #t1
where ref = #value
set #len = (select count(ref) from #t1)
end
select * from #t2
Java code
....
String query = "Execute [p2]";
try(CallableStatement cstmt = conn.prepareCall(query);
ResultSet rs = cstmt.executeQuery()){
... some code
}
The table variable #t1 hold select result from a table 'table1'
The variable #len hold the number of rows in #t1
Using #len > 0 as condition in while loop, I want to select records from another table 'table2' the table variable #t2 hold the select records from 'table2'
The delete statement removes value from #t1
#len set to new number of rows in #t1
the last statement return all the records store in #t2
The first procedure works fine, but the second procedure works only in SQL Server.
I get this an error message in my java application
statement did not return a resultset
I want this to return a result set with the select statement I have at the
end of the query.
Please is there a way around this?
Your [p2] stored procedure needs to include SET NOCOUNT ON right at the beginning to suppress the "n rows affected" counts so JDBC doesn't get confused as to what it should put into the ResultSet:
CREATE PROCEDURE p2
AS
SET NOCOUNT ON;
declare #t1 table(
ref varchar(20)
)
-- ... and so on
For more information on SET NOCOUNT see
SET NOCOUNT (Transact-SQL)
For more information on precisely what gets returned from a stored procedure call, see
How to get everything back from a stored procedure using JDBC
use method "execute" instead of "executeQuery".
I have a requirement to insert multiple rows into table1 and at the same time insert a row into table2 with a pkID from table1 and a value that comes from a SP parameter.
I created a stored procedure that performs a batch insert with a table valued parameter which contains the rows to be inserted into table1. But I have a problem with inserting the row into table2 with the corresponding Id (identity) from table1, along with parameter value that I have passed.
Is there anyone who implemented this, or what is the good solution for this?
CREATE PROCEDURE [dbo].[oSP_TV_Insert]
#uID int
,#IsActive int
,#Type int -- i need to insert this in table 2
,#dTableGroup table1 READONLY -- this one is a table valued
AS
DECLARE #SQL varchar(2000)
DECLARE #table1Id int
BEGIN
INSERT INTO dbo.table1
(uID
,Name
,Contact
,Address
,City
,State
,Zip
,Phone
,Active)
SELECT
#uID
,Name
,Contact
,Address
,City
,State
,Zip
,Phone
,Active
,#G_Active
FROM #dTableGroup
--the above query will perform batch insert using the records from dTableGroup which is table valued
SET #table1ID = SCOPE_IDENTITY()
-- this below will perform inserting records to table2 with every Id inserted in table1.
Insert into table2(#table1ID , #type)
You need to temporarily store the inserted identity values and then create a second INSERT statement - using the OUTPUT clause.
Something like:
-- declare table variable to hold the ID's that are being inserted
DECLARE #InsertedIDs TABLE (ID INT)
-- insert values into table1 - output the inserted ID's into #InsertedIDs
INSERT INTO dbo.table1(ID, Name, Contact, Address, City, State, Zip, Phone, Active)
OUTPUT INSERTED.ID INTO #InsertedIDs
SELECT
#ID, Name, Contact, Address, City, State, Zip, Phone, Active, #G_Active
FROM #dTableGroup
and then you can have your second INSERT statement:
INSERT INTO dbo.table2(Table1ID, Type)
SELECT ID, #type FROM #InsertedIDs
See the MSDN docs on the OUTPUT clause for more details on what you can do with the OUTPUT clause - one of the most underused and most "unknown" features of SQL Server these days!
Another approach using OUTPUT clause and only one statement for inserting data in both destination tables:
--Parameters
DECLARE #TableGroup TABLE
(
Name NVARCHAR(100) NOT NULL
,Phone VARCHAR(10) NOT NULL
);
DECLARE #Type INT;
--End Of parameters
--Destination tables
DECLARE #FirstDestinationTable TABLE
(
FirstDestinationTableID INT IDENTITY(1,1) PRIMARY KEY
,Name NVARCHAR(100) NOT NULL
,Phone VARCHAR(10) NOT NULL
);
DECLARE #SecondDestinationTable TABLE
(
SecondDestinationTable INT IDENTITY(2,2) PRIMARY KEY
,FirstDestinationTableID INT NOT NULL
,[Type] INT NOT NULL
,CHECK([Type] > 0)
);
--End of destination tables
--Test1
--initialization
INSERT #TableGroup
VALUES ('Bogdan SAHLEAN', '0721200300')
,('Ion Ionescu', '0211002003')
,('Vasile Vasilescu', '0745600800');
SET #Type = 9;
--execution
INSERT #SecondDestinationTable (FirstDestinationTableID, [Type])
SELECT FirstINS.FirstDestinationTableID, #Type
FROM
(
INSERT #FirstDestinationTable (Name, Phone)
OUTPUT inserted.FirstDestinationTableID
SELECT tg.Name, tg.Phone
FROM #TableGroup tg
) FirstINS
--check records
SELECT *
FROM #FirstDestinationTable;
SELECT *
FROM #SecondDestinationTable;
--End of test1
--Test2
--initialization
DELETE #TableGroup;
DELETE #FirstDestinationTable;
DELETE #SecondDestinationTable;
INSERT #TableGroup
VALUES ('Ion Ionescu', '0210000000')
,('Vasile Vasilescu', '0745000000');
SET #Type = 0; --Wrong value
--execution
INSERT #SecondDestinationTable (FirstDestinationTableID, [Type])
SELECT FirstINS.FirstDestinationTableID, #Type
FROM
(
INSERT #FirstDestinationTable (Name, Phone)
OUTPUT inserted.FirstDestinationTableID
SELECT tg.Name, tg.Phone
FROM #TableGroup tg
) FirstINS
--check records
DECLARE #rc1 INT, #rc2 INT;
SELECT *
FROM #FirstDestinationTable;
SET #rc1 = ##ROWCOUNT;
SELECT *
FROM #SecondDestinationTable;
SET #rc2 = ##ROWCOUNT;
RAISERROR('[Test2 results] #FirstDestinationTable: %d rows; ##SecondDestinationTable: %d rows;',1,1,#rc1,#rc2);
--End of test1
Since you need all inserted identity values, look at the output clause of the insert statement: http://msdn.microsoft.com/en-us/library/ms177564.aspx