SQL insert statement for each update row - sql

Now i made cursor to update in 2 tables and insert in one table based on specific select statement this select statement return 2 columns x , y i need x to update in table "PX" because x is Primary key in this table and need x to update in table "FX" because x is foreign key in this table then insert in third table x data.
I need to change this cursor and use update and insert script i tried but i found that i need to make loop to achieve my target so if any one know if i can change this cursor .
And thanks in advance
DECLARE #id int
DECLARE #clientid uniqueidentifier
DECLARE #code int
DECLARE #Wtime int
DECLARE #closeComplaint CURSOR
SET #closeComplaint = CURSOR FAST_FORWARD
FOR
SELECT ComplaintId, [ClientId]
FROM complaint
WHERE ComplaintStatusId = 5
AND (waitingForCutomerCloseDateTime < GETDATE() OR
waitingForCutomerCloseDateTime = GETDATE())
OPEN #closeComplaint
FETCH NEXT FROM #closeComplaint INTO #id, #clientid
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT
waitingForCutomerCloseTime = #Wtime
FROM
SystemConfiguration
WHERE
ClientId = #clientid
SELECT
[Code] = #code
FROM
[dbo].[resp_users]
WHERE
ClientId = #clientid
UPDATE activity
SET ActivityStatus = 4,
CompletionDate = GETDATE(),
ClosedBy = #code
WHERE [ComplaintId] = #id
UPDATE [dbo].[Complaint]
SET ComplaintStatusId = 2
WHERE [ComplaintId] = #id
INSERT INTO [dbo].[Note] ([Note_Description], [ClientId], [User_Code], [Visible_Internal],
[ComplaintId], [Note_DateTime], [ComplainantId],
[OneStopDesk_CustomerEmail], [OneStopDesk_CustomerUsername], [Private])
VALUES (N'Automatically closed by system after ' + #Wtime, #clientid, #code, 1,
#id, GETDATE(), null, null, null, 1)
FETCH NEXT FROM #closeComplaint INTO #id, #clientid
END
CLOSE #closeComplaint
DEALLOCATE #closeComplaint

I'm not entirely sure I got everything right (you didn't post the table structures, so I can really only guess at times how those tables are connected) - but you should be able to basically do all of this in 3 simple, set-based statements - and that should be a LOT faster than the cursor!
-- declare table variable
DECLARE #Input TABLE (CompaintID INT, ClientID INT)
-- save the rows into a table variable
INSERT INTO #Input (ComplaintID, ClientID)
SELECT ComplaintID, ClientID
FROM dbo.Complaint
WHERE ComplaintStatusId = 5
AND waitingForCustomerCloseDateTime <= GETDATE()
UPDATE a
SET ActivityStatus = 4,
CompletionDate = GETDATE(),
ClosedBy = u.Code
FROM dbo.Activity a
INNER JOIN #Input i ON a.ComplaintId = i.ComplaintId
INNER JOIN dbo.resp_users u ON i.ClientId = u.ClientId
UPDATE dbo.Complaint
SET ComplaintStatusId = 2
WHERE
ComplaintStatusId = 5
AND waitingForCustomerCloseDateTime <= GETDATE()
INSERT INTO dbo.Note ([Note_Description], [ClientId], [User_Code], [Visible_Internal],
[ComplaintId], [Note_DateTime], [ComplainantId],
[OneStopDesk_CustomerEmail], [OneStopDesk_CustomerUsername], [Private])
SELECT
N'Automatically closed by system after ' + sc.waitingForCustomerCloseTime,
i.ClientId, u.Code, 1,
i.ComplaintId, GETDATE(), null, null, null, 1
FROM
#Input i
INNER JOIN
dbo.SystemConfiguration sc ON i.ClientId = sc.ClientId
INNER JOIN
dbo.resp_user u ON u.ClientId = i.ClientId

Related

Looking for missing gaps for getting "Only one expression can be specified in the select list when the subquery is not introduced with EXISTS."

I have the following query to find missing gaps in the sort for each ModelID but I keep getting the following error and don't know why.
What I'm doing is in my first loop I am looping through the modelID's and in the inner loop I am looking for the missing gaps in the siSort column for that modelID and putting that into a temp table.
Msg 116, Level 16, State 1, Line 27
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
USE crm
GO
BEGIN
DECLARE #ID INT
DECLARE #MAXID INT
DECLARE #COUNT INT
DECLARE #iCustomListModelID INT
DECLARE #iCustomFieldID INT
DECLARE #MissingIds TABLE (ID INT)
DECLARE #Output TABLE (iCustomListModelID INT, siSort INT, iListItemID INT)
-- SELECT ALL DISTINCT ICustomListModelID's FROM CustomList Table
SELECT DISTINCT cl.iCustomListModelID
INTO #DistinctModelIDs
FROM dbo.CustomListModel clm
INNER JOIN dbo.CustomListType clt ON clm.iCustomListTypeID = clt.iCustomListTypeID
AND clt.vchCustomListTypeDescription = N'Household Custom Field'
INNER JOIN dbo.CustomList cl ON clm.iCustomListModelID = cl.iCustomListModelID
INNER JOIN dbo.CustomField cf ON cl.iListItemID = cf.iCustomFieldID
ORDER BY cl.iCustomListModelID
-- Get iCustomFieldID to insert into iListItemID
SET #iCustomFieldID = (SELECT * FROM dbo.CustomField cf WHERE vchLabel = '')
-- Begin Outer loop to go through each iCustomListModelID
WHILE (SELECT COUNT(iCustomListModelID) AS Total FROM #DistinctModelIDs) > 0
BEGIN
-- GRAB THE NEXT iCustomListModelID
SELECT #iCustomListModelID = (SELECT TOP 1 iCustomListModelID FROM #DistinctModelIDs);
DROP TABLE #List
SELECT siSort INTO #List FROM CustomList WHERE iCustomListModelID = #iCustomListModelID
SELECT #MAXID = siSort FROM dbo.CustomList WHERE iCustomListModelID = #iCustomListModelID
SET #ID = 1;
-- Inner loop to go through the missing gaps in siSort
WHILE #ID <= #MAXID
BEGIN
IF NOT EXISTS (
SELECT 'X' FROM #List WHERE siSort = #ID
)
INSERT INTO #MissingIDs (ID)
VALUES (#ID)
--INSERT THE MISSING ID INTO #outputTable Table
INSERT INTO #Output (iCustomListModelID, siSort, iListItemID)
VALUES (#iCustomListModelID, #ID, #iCustomFieldID)
SET #ID = #ID + 1;
END;
-- DELETE CURRENT iCustomListModelID
DELETE FROM #DistinctModelIDs WHERE iCustomListModelID = #iCustomListModelID
END
SELECT * FROM #Output
END;
One possibility is that the issue is this line:
SET #iCustomFieldID = (SELECT * FROM dbo.CustomField cf WHERE vchLabel = '')
If dbo.CustomerField doesn't have exactly one column (more than one column seems likely because vchLabel is already one column in the table), then this will generate an error of that type.

Insert Data into Table if a condition is true

SQL statement Question
I have an instance where I need to insert one record multiple times in a DB table that contains a unique reference column. I'm declaring a variable and using a select statement to populate variable and then running an insert statement. The issue is that when grabbing unique value into variable it only grabs the last record in the reference table. I need for insert statement to insert at each point where a record is found.
DECLARE #ID INT;
DECLARE #RuleID INT;
SELECT #RuleID = RuleID from Rules where Rule_Name = 'VERSION_ID' and Field = 'TSH'
SELECT #ID = ID FROM CHANNELS WHERE SUBSTRING(CHANNEL_NAME,0,4) != 'HEL'
BEGIN
INSERT INTO Rule_Items
VALUES(#ID,#RuleID,0,'2.5.1','E','A',0,getdate())
END
If you want all combinations, you can use insert . . . select with a cross join:
INSERT INTO Rule_Items
select c.id, r.ruleid, 0, '2.5.1', 'E', 'A', 0, getdate()
from rules r cross join
channels c
where r.Rule_Name = 'VERSION_ID' and r.Field = 'TSH' and
SUBSTRING(c.CHANNEL_NAME, 0, 4) <> 'HEL';
I decided to use a cursor and create a temp table. Here is query that worked.
**--BEGIN TRAN
DECLARE #Channelid INT
DECLARE #RuleID INT
SELECT #RuleID = RuleID From Rules Where Rule_Name = 'VERSION_ID'
DECLARE GetChannelId CURSOR FOR SELECT Channelid FROM HL7_Channels WHERE Channel_Name not like 'MU2%' AND Channel_Description LIKE '%outbound%'
OPEN GetChannelId
FETCH GetChannelId INTO #Channelid
WHILE (##FETCH_STATUS = 0)
BEGIN
IF NOT EXISTS (Select 1 From Rule_Items Where ChannelId = #Channelid AND RuleID = #RuleID)
BEGIN
INSERT INTO Rule_Items VALUES (#Channelid,#RuleID,0,'2.5.1','E','A',0,getdate())
END
FETCH GetChannelId INTO #Channelid
CONTINUE
END
CLOSE GetChannelId
DEALLOCATE GetChannelId
--ROLLBACK TRAN
--COMMIT TRAN**

Loop through all the rows of a temp table and call a stored procedure for each row

I have declared a temp table to hold all the required values as follows:
DECLARE #temp TABLE
(
Password INT,
IdTran INT,
Kind VARCHAR(16)
)
INSERT INTO #temp
SELECT s.Password, s.IdTran, 'test'
from signal s inner join vefify v
on s.Password = v.Password
and s.IdTran = v.IdTran
and v.type = 'DEV'
where s.[Type] = 'start'
AND NOT EXISTS (SELECT * FROM signal s2
WHERE s.Password = s2.Password
and s.IdTran = s2.IdTran
and s2.[Type] = 'progress' )
INSERT INTO #temp
SELECT s.Password, s.IdTran, 'test'
FROM signal s inner join vefify v
on s.Password = v.Password
and s.IdTran = v.IdTran
and v.type = 'PROD'
where s.[Type] = 'progress'
AND NOT EXISTS (SELECT * FROM signal s2
WHERE s.Password = s2.Password
and s.IdTran = s2.IdTran
and s2.[Type] = 'finish' )
Now i need to loop through the rows in the #temp table and and for each row call a sp that takes all the parameters of #temp table as input.
How can I achieve this?
you could use a cursor:
DECLARE #id int
DECLARE #pass varchar(100)
DECLARE cur CURSOR FOR SELECT Id, Password FROM #temp
OPEN cur
FETCH NEXT FROM cur INTO #id, #pass
WHILE ##FETCH_STATUS = 0 BEGIN
EXEC mysp #id, #pass ... -- call your sp here
FETCH NEXT FROM cur INTO #id, #pass
END
CLOSE cur
DEALLOCATE cur
Try returning the dataset from your stored procedure to your datatable in C# or VB.Net. Then the large amount of data in your datatable can be copied to your destination table using a Bulk Copy. I have used BulkCopy for loading large datatables with thousands of rows, into Sql tables with great success in terms of performance.
You may want to experiment with BulkCopy in your C# or VB.Net code.
something like this?
DECLARE maxval, val, #ind INT;
SELECT MAX(ID) as maxval FROM table;
while (ind <= maxval ) DO
select `value` as val from `table` where `ID`=ind;
CALL fn(val);
SET ind = ind+1;
end while;
You can do something like this
Declare #min int=0, #max int =0 --Initialize variable here which will be use in loop
Declare #Recordid int,#TO nvarchar(30),#Subject nvarchar(250),#Body nvarchar(max) --Initialize variable here which are useful for your
select ROW_NUMBER() OVER(ORDER BY [Recordid] ) AS Rownumber, Recordid, [To], [Subject], [Body], [Flag]
into #temp_Mail_Mstr FROM Mail_Mstr where Flag='1' --select your condition with row number & get into a temp table
set #min = (select MIN(Rownumber) from #temp_Mail_Mstr); --Get minimum row number from temp table
set #max = (select Max(Rownumber) from #temp_Mail_Mstr); --Get maximum row number from temp table
while(#min <= #max)
BEGIN
select #Recordid=Recordid, #To=[To], #Subject=[Subject], #Body=Body from #temp_Mail_Mstr where Rownumber=#min
-- You can use your variables (like #Recordid,#To,#Subject,#Body) here
-- Do your work here
set #min=#min+1 --Increment of current row number
END
You always don't need a cursor for this. You can do it with a while loop. You should avoid cursors whenever possible. While loop is faster than cursors.

Loop through a recordset and use the result to do another SQL select and return the results

I am completely new to stored procedure. This time, I need to create a stored procedure in MS SQL.
Let's say I have the following table.
Table name: ListOfProducts
--------------------------
SomeID, ProductID
34, 4
35, 8
35, 11
How do I pass in a SomeID. Use this SomeID to select a recordset from table, ListOfProducts. Then loop through this record set.
Let's say I pass in SomeID = 35.
So, the record set will return 2 records with SomeID 35. In the loop, I will get ProductID 8 and 11, which will be used to do another select from another table.
The stored procedure should return the results from the 2nd select.
How can I do this in MS SQL stored procedure?
Sorry, for this newbie question. Thanks for any help.
If you want looping through the records. You can do like:
--Container to Insert Id which are to be iterated
Declare #temp1 Table
(
tempId int
)
--Container to Insert records in the inner select for final output
Declare #FinalTable Table
(
Id int,
ProductId int
)
Insert into #temp1
Select Distinct SomeId From YourTable
-- Keep track of #temp1 record processing
Declare #Id int
While((Select Count(*) From #temp1)>0)
Begin
Set #Id=(Select Top 1 tempId From #temp1)
Insert Into #FinalTable
Select SomeId,ProductId From ListOfProducts Where Id=#Id
Delete #temp1 Where tempId=#Id
End
Select * From #FinalTable
There is probably no point in writing an explicit loop if you don't need to preform some action on the products that can't be done on the whole set. SQL Server can handle stuff like this much better on its own. I don't know what your tables look like, but you should try something that looks more like this.
CREATE PROC dbo.yourProcName
#SomeID int
AS
BEGIN
SELECT
P.ProductId,
P.ProductName
FROM
Product P
JOIN
ListOfProducts LOP
ON LOP.ProductId = P.ProductId
WHERE
LOP.SomeId = #SomeID
END
I had to do something similar in order to extract hours from a select resultset start/end times and then create a new table iterating each hour.
DECLARE #tCalendar TABLE
(
RequestedFor VARCHAR(50),
MeetingType VARCHAR(50),
RoomName VARCHAR(MAX),
StartTime DATETIME,
EndTime DATETIME
)
INSERT INTO #tCalendar(RequestedFor,MeetingType,RoomName,StartTime,EndTime)
SELECT req as requestedfor
,meet as meetingtype
,room as rooms
,start as starttime
,end as endtime
--,u.datetime2 as endtime
FROM mytable
DECLARE #tCalendarHours TABLE
(
RequestedFor VARCHAR(50),
MeetingType VARCHAR(50),
RoomName VARCHAR(50),
Hour INT
)
DECLARE #StartHour INT,#EndHour INT, #StartTime DATETIME, #EndTime DATETIME
WHILE ((SELECT COUNT(*) FROM #tCalendar) > 0)
BEGIN
SET #StartTime = (SELECT TOP 1 StartTime FROM #tCalendar)
SET #EndTime = (SELECT TOP 1 EndTime FROM #tCalendar)
SET #StartHour = (SELECT TOP 1 DATEPART(HOUR,DATEADD(HOUR,0,StartTime)) FROM #tCalendar)
SET #EndHour = (SELECT TOP 1 DATEPART(HOUR,DATEADD(HOUR,0,EndTime)) FROM #tCalendar)
WHILE #StartHour <= #EndHour
BEGIN
INSERT INTO #tCalendarHours
SELECT RequestedFor,MeetingType,RoomName,#StartHour FROM #tCalendar WHERE StartTime = #StartTime AND EndTime = #EndTime
SET #StartHour = #StartHour + 1
END
DELETE #tCalendar WHERE StartTime = #StartTime AND EndTime = #EndTime
END
Do something like this:
Declare #ID int
SET #ID = 35
SELECT
p.SomeID
,p.ProductID
FROM ListOfProducts p
WHERE p.SomeID = #ID
-----------------------
--Or if you have to join to get it
Declare #ID int
SET #ID = 35
SELECT
c.SomeID
,p.ProductID
,p.ProductName
FROM ListOfProducts p
INNER JOIN categories c on p.ProductID = c.SomeID
WHERE p.SomeID = #ID
You can use option with WHILE loop and BREAK/CONTINUE keywords
CREATE PROC dbo.yourProcName
#SomeID int
AS
BEGIN
IF OBJECT_ID('tempdb.dbo.#resultTable') IS NOT NULL DROP TABLE dbo.#resultTable
CREATE TABLE dbo.#resultTable
(Col1 int, Col2 int)
DECLARE #ProductID int = 0
WHILE(1=1)
BEGIN
SELECT #ProductID = MIN(ProductID)
FROM ListOfProducts
WHERE SomeID = #SomeID AND ProductID > #ProductID
IF #ProductID IS NULL
BREAK
ELSE
INSERT dbo.#resultTable
SELECT Col1, Col2
FROM dbo.yourSearchTable
WHERE ProductID = #ProductID
CONTINUE
END
SELECT *
FROM dbo.#resultTable
END
Demo on SQLFiddle

within a sql while loop, get id of last inserted row then insert it into a different table, using OUTPUT?

I am writing some sql, using sql server 2008, to loop around some records. Within this loop I need to insert a row and the ID of that row will be put into a field in an existing record in a different table. I thought I would be able to achieve this with OUTPUT but I couldn't find an example of exactly what I wanted to do.
Here's what I have so far:
DECLARE #courseTempID INT
DECLARE #courseID INT
DECLARE #academicYearID INT
DECLARE #courseCode VARCHAR(10)
DECLARE #uio_id INT
DECLARE #creatorIntranetUserID INT
WHILE (SELECT count(*) FROM CoursesTemp WHERE dmprocessed = 0) > 0
BEGIN
SELECT TOP 1 #id = courseTempID FROM CoursesTemp WHERE dmprocessed = 0
SELECT TOP 1 #academicYearID = academicYearID FROM CoursesTemp WHERE dmprocessed = 0
SELECT TOP 1 #courseCode = courseCode FROM CoursesTemp WHERE dmprocessed = 0
SELECT TOP 1 #uio_id = uio_id FROM CoursesTemp WHERE dmprocessed = 0
SELECT TOP 1 #creatorIntranetUserID = creatorIntranetUserID FROM CoursesTemp WHERE dmprocessed = 0
INSERT INTO dbo.Courses VALUES(3,#academicYearID,1,#courseCode,#uio_id,GETDATE(),#creatorIntranetUserID)
OUTPUT INSERTED.courseID INTO #courseID
UPDATE CoursesTemp SET dmprocessed = 1, courseID = #courseID WHERE courseTempID = #courseTempID
END
The error I am getting is "Incorrect syntax near 'INSERTED'".
Can anyone help me work out how to use OUTPUT in this way please?
A few performance improvements applied. It is safer to use SCOPE_IDENTITY()
DECLARE #courseTempID INT
DECLARE #courseID INT
DECLARE #academicYearID INT
DECLARE #courseCode VARCHAR(10)
DECLARE #uio_id INT
DECLARE #creatorIntranetUserID INT
DECLARE #id INT
WHILE EXISTS(SELECT 1 FROM CoursesTemp WHERE dmprocessed = 0)
BEGIN
SELECT TOP 1 #id = courseTempID
,#academicYearID = academicYearID
,#courseCode = courseCode
,#uio_id = uio_id
,#creatorIntranetUserID = creatorIntranetUserID
FROM CoursesTemp WHERE dmprocessed = 0
INSERT INTO dbo.Courses VALUES(3,#academicYearID,1,#courseCode,#uio_id,GETDATE(),#creatorIntranetUserID)
UPDATE CoursesTemp SET dmprocessed = 1, courseID = SCOPE_IDENTITY() WHERE courseTempID = #courseTempID
END
OUTPUT needs to go between INSERT INTO dbo.Courses and VALUES(...)
You also have OUTPUT INSERTED.courseID INTO #CourseId but #CourseId is an int variable, it needs to be the table you want to insert into.
EDIT I've reread what you're tying to do. Instead of using OUTPUT, you can change your last line to
UPDATE CoursesTemp SET dmprocessed = 1, courseId = SCOPE_IDENTITY()
WHERE courseTempID = #courseTempID
You may be able to use ##IDENTITY to retrieve the last-inserted ID value. http://msdn.microsoft.com/en-us/library/ms187342.aspx