Cursor insert to identical rows instead of one - tsql
I'm trying to handle some active requests using Cursor:
DECLARE #ID bigint --id attachments
DECLARE #personID BIGINT
DECLARE #territoryServiceID BIGINT
DECLARE #isAtClosed BIT
DECLARE #currentServerDate DATETIME = '2016-01-01 01:10:00.000' --this change GETDATE()
DECLARE #BeginDate DATETIME SET #BeginDate = #currentServerDate
DECLARE #periodYear INT SET #periodYear = DATEPART(YEAR,#currentServerDate) - 1
DECLARE cur cursor LOCAL STATIC
FOR
SELECT at.id, at.personID, at.territoryServiceID, ts.isClosing
FROM Attachments at
INNER JOIN Person p ON p.id = at.personID AND p.parentID IS NULL
INNER JOIN TerritoryServices ts ON ts.id = at.territoryServiceID
LEFT JOIN Attachments at2 ON at2.personID = at.personID AND at2.parentID = at.id AND at2.attachmentStatusID IN (2,11,12)
WHERE at.attachmentStatusID = 1 AND at.causeOfAttachID = 8 AND at.endDate IS NOT NULL
AND at2.id IS NULL
AND p.id IN (15300000019296419,15300000018501113,15300000014988209,414674754,420940229,409531785)
OPEN cur
FETCH NEXT FROM cur INTO #ID, #personID, #territoryServiceID, #isAtClosed
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #personID_NVARCHAR NVARCHAR(MAX) SET #personID_NVARCHAR = CONVERT(NVARCHAR(MAX),#personID)
PRINT '1 ('+#personID_NVARCHAR+')'
IF (#isAtClosed = 1) -- if ter of CA is closing
BEGIN
-- Insert error into ErrorHandlingCampainOfAttach
DECLARE #ErrorDescr NVARCHAR(MAX) SET #ErrorDescr = 'TerId: ' + CONVERT(NVARCHAR(MAX),#territoryServiceID)
INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description])
VALUES (#ID, #personID, #territoryServiceID, #periodYear, 1, GETDATE(), #ErrorDescr)
END
ELSE
BEGIN
DECLARE #terAt2ID BIGINT
DECLARE #isAt2Close BIT = 0
SELECT #isAt2Close = ts.isClosing, #terAt2ID = ts.id FROM Attachments at
INNER JOIN TerritoryServices ts ON ts.id = at.territoryServiceID
WHERE at.personID = #personID AND at.attachmentStatusID = 2 AND at.endDate IS NULL
IF (#isAt2Close = 1) -- if ter of attach is closing
BEGIN
-- Insert error into ErrorHandlingCampainOfAttach
DECLARE #ErrorDescr2 NVARCHAR(MAX) SET #ErrorDescr2 = 'TerAttachId: ' + CONVERT(NVARCHAR(MAX),#terAt2ID)
INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description])
VALUES (#ID, #personID, #territoryServiceID, #periodYear, 2, GETDATE(), #ErrorDescr2)
END
ELSE
BEGIN
BEGIN TRY
BEGIN TRANSACTION TranName
-- Search active request
DECLARE #ID_zapros BIGINT
SELECT #ID_zapros = id FROM Attachments WHERE personID = #personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != #ID
IF (#ID_zapros IS NOT NULL)
BEGIN
-- Canseled request
-- Block #1
-- Create cancel for active request
INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID,
causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID,
actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num)
SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID, at.doctorID,
8,at.careAtHome,NULL,NULL, 11, #BeginDate, #BeginDate, at.id,
at.userID, at.registratorID, at.actualAttachmentID, NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num
FROM Attachments at
WHERE at.id = #ID_zapros
-- Set endDate for active request
UPDATE Attachments SET endDate = #BeginDate WHERE id = #ID_zapros
END
--Search active attach
DECLARE #ID_prikrep BIGINT
SELECT #ID_prikrep = id FROM Attachments WHERE personID = #personID AND endDate IS NULL AND attachmentStatusID = 2
IF (#ID_prikrep IS NOT NULL)
BEGIN
-- Block #2
-- Insert detach
INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID,
causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID,
actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num)
SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID, at.doctorID,
8,at.careAtHome,NULL,NULL, 8, #BeginDate, #BeginDate, at.id,
at.userID, at.registratorID, at.actualAttachmentID, NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num
FROM Attachments at
WHERE at.id = #ID_prikrep
--Set endDate for active attach
UPDATE Attachments SET endDate = #BeginDate WHERE id = #ID_prikrep
END
-- Attach CA
INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID,
causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID,
actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num)
SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID, at.doctorID,
8,at.careAtHome,NULL,NULL, 2, #BeginDate, NULL, at.id,
at.userID, at.registratorID, at.actualAttachmentID, NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num
FROM Attachments at
WHERE at.id = #ID
COMMIT TRANSACTION TranName
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION TranName
-- Insert error into ErrorHandlingCampainOfAttach
INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description])
VALUES (#ID, #personID, #territoryServiceID, #periodYear, 3, GETDATE(),ERROR_MESSAGE())
END CATCH
END
END
FETCH NEXT FROM cur INTO #ID, #personID, #territoryServiceID, #isAtClosed
END
CLOSE cur
DEALLOCATE cur
But sometimes the result is inserted into two rows instead of one, in block statement "Create cancel for active request" (Block #1) or "Insert detach" (Block #2). Each run on the same recording is done in different ways, sometimes OK, sometimes duplicated entry in the block #1, block #2 times. For some reason, one of the inserts is performed twice, but not always.
Please tell me what is the reason for this behavior
It turned out pretty simple:
DECLARE #ID_zapros BIGINT
SELECT #ID_zapros = id FROM Attachments WHERE personID = #personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != #ID
When this query returns NULL is written into the variable the previous value and not NULL. The solution to this problem reset the variable after insert statement or before set:
DECLARE #ID_zapros BIGINT
SELECT #ID_zapros = id FROM Attachments WHERE personID = #personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != #ID
IF (#ID_zapros IS NOT NULL)
BEGIN
INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID,
causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID,
actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num)
SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID, at.doctorID,
8,at.careAtHome,NULL,NULL, 11, #BeginDate, #BeginDate, at.id,
at.userID, at.registratorID, at.actualAttachmentID, NULL,#nvar_ID,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num
FROM Attachments at
WHERE at.id = #ID_zapros
UPDATE Attachments SET endDate = #BeginDate WHERE id = #ID_zapros
SET #ID_zapros = NULL
END
... or
DECLARE #ID_zapros BIGINT
SET #ID_zapros = NULL
SELECT #ID_zapros = id FROM Attachments WHERE personID = #personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != #ID
IF (#ID_zapros IS NOT NULL)
BEGIN
INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID,
causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID,
actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num)
SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID, at.doctorID,
8,at.careAtHome,NULL,NULL, 11, #BeginDate, #BeginDate, at.id,
at.userID, at.registratorID, at.actualAttachmentID, NULL,#nvar_ID,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num
FROM Attachments at
WHERE at.id = #ID_zapros
UPDATE Attachments SET endDate = #BeginDate WHERE id = #ID_zapros
END
Related
I cannot manage to insert multiple rows when having multiple fields to get data from
I ran into a problem with regards to trying to insert multiple rows in a table at once. I know it sounds easy, but here is the twist. The procedure itself gets data from a trigger, and the trigger returns a number of rows. So i need to make 1 insert statement to insert those rows and some other data. here is the code: CREATE PROCEDURE [a01].[usp_raiseFriendAlerts] (#AccountA UNIQUEIDENTIFIER, #AccountB UNIQUEIDENTIFIER) AS BEGIN DECLARE #typeID TINYINT; DECLARE #notificationID UNIQUEIDENTIFIER = NEWID(); DECLARE #accountAName NVARCHAR(356); DECLARE #accountBName NVARCHAR(356); SET #typeID = ( SELECT typeID FROM [a01].[tbl_notificationTypes] WHERE typeName = 'Added friend'); SET #accountAName = ( SELECT accountUsername FROM [a01].[tbl_userAccounts] WHERE accountID = #AccountA); SET #accountBName = ( SELECT accountUsername FROM [a01].[tbl_userAccounts] WHERE accountID = #AccountB); DECLARE #AccountIDZZ UNIQUEIDENTIFIER; SET #AccountIDZZ = (SELECT friendAccountID FROM [a01].[udf_getAddedFriendContacts](#AccountA, #AccountB) EXCEPT SELECT targetAccountID FROM [a01].[tbl_blockedAccounts]); INSERT INTO [a01].[tbl_notificationsInbox] (notificationID, notificationMessage, notificationDate, accountID, typeId) VALUES (#notificationID, #accountAName + ' is now friends with ' + #accountBName, SYSDATETIMEOFFSET(), #AccountIDZZ , #typeID) END; GO
Try this: CREATE PROCEDURE [a01].[usp_raiseFriendAlerts] ( #AccountA UNIQUEIDENTIFIER , #AccountB UNIQUEIDENTIFIER ) AS BEGIN DECLARE #typeID TINYINT , #notificationID UNIQUEIDENTIFIER = NEWID() , #accountAName NVARCHAR(356) , #accountBName NVARCHAR(356) , #AccountIDZZ UNIQUEIDENTIFIER; SELECT #typeID = typeID FROM [a01].[tbl_notificationTypes] WHERE typeName = 'Added friend'; SELECT #accountAName = accountUsername FROM [a01].[tbl_userAccounts] WHERE accountID = #AccountA; SELECT #accountBName = accountUsername FROM [a01].[tbl_userAccounts] WHERE accountID = #AccountB; INSERT INTO [a01].[tbl_notificationsInbox] ( notificationID , notificationMessage , notificationDate , accountID , typeId ) SELECT #notificationID , #accountAName + ' is now friends with ' + #accountBName , SYSDATETIMEOFFSET() , AIDZZ.accountID , #typeID FROM ( SELECT friendAccountID AS 'accountID' FROM [a01].[udf_getAddedFriendContacts](#AccountA, #AccountB) EXCEPT SELECT targetAccountID AS 'accountID' FROM [a01].[tbl_blockedAccounts] ) AS AIDZZ END; GO
How to fill column basing on two other columns
I have table LessonHour with empty Number column. TABLE [dbo].[LessonHour] ( [Id] [uniqueidentifier] NOT NULL, [StartTime] [time](7) NOT NULL, [EndTime] [time](7) NOT NULL, [SchoolId] [uniqueidentifier] NOT NULL, [Number] [int] NULL ) How can I fill up the table with Number for each LessonHour so it would be the number of lesson hour in order? The LessonHours cannot cross each other. Every school has defined its own lesson hour schema. Example set of data http://pastebin.com/efWCtUbv What'd I do: Order by SchoolId and StartTime Use Cursor to insert into row next number, starting from 1 every time the SchoolId changes. Edit: Solution with cursor select -- top 20 LH.[Id], [StartTime], [EndTime], [SchoolId] into #LH from LessonHour as LH join RowStatus as RS on LH.RowStatusId = RS.Id where RS.IsActive = 1 select * from #LH order by SchoolId, StartTime declare #id uniqueidentifier, #st time(7), #et time(7), #sid uniqueidentifier declare #prev_sid uniqueidentifier = NEWID() declare #i int = 1 declare cur scroll cursor for select * from #LH order by SchoolId, StartTime open cur; fetch next from cur into #id, #st, #et, #sid while ##FETCH_STATUS = 0 begin --print #prev_sid if #sid <> #prev_sid begin set #i = 1 end update LessonHour set Number = #i where Id = #id print #i set #i = #i + 1 set #prev_sid = #sid fetch next from cur into #id, #st, #et, #sid end; close cur; deallocate cur; drop table #LH This is the result I was after http://pastebin.com/iZ8cnA6w
Merging the information from the StackOverflow questions SQL Update with row_number() and How do I use ROW_NUMBER()?: with cte as ( select number, ROW_NUMBER() OVER(partition by schoolid order by starttime asc) as r from lessonhour ) update cte set number = r
Would this work CREATE TABLE [dbo].[LessonHour] ( [Id] [uniqueidentifier] NOT NULL, [StartTime] [time](7) NOT NULL, [EndTime] [time](7) NOT NULL, [SchoolId] [uniqueidentifier] NOT NULL, [Number] AS DATEDIFF(hour,[StartTime],[EndTime]) ) So if I understand the question correctly you require a calculated column which takes in the values of [StartTime] and [EndTime] and returns the number of hours for that lesson as an int. The above table definition should do the trick.
Associating a variable with a tmptable
declare #count int = 0 while #count< 5 BEGIN IF '#temptable%' = (SELECT name FROM tempdb.sys.columns WHERE column_name = 'Butter') set #table1 = 'temptable%' else '#temptable%' = (SELECT name FROM tempdb.sys.columns WHERE column_name = 'Parrot') set #table2 = 'temptable%' set #count= #count+ 1 END So I have five temporary tables with the name #temptable1, #temptable2, etc. and would like to distinguish the them from each other and set them to a variable depending on the unique column_name (ie. #temptable1 will be associated with the variable #table1). So is there a way I can call #table1 and then have it return #temptable1?
INSERT query from trigger inserts NULL
I have the following query in SQL Server 2005: DECLARE #issueid numeric(10,0) DECLARE #domain nvarchar (255) SET #issueid = (SELECT issueid FROM issues WHERE issueid = 4850) SET #domain = (SELECT fielddata FROM customfielddata WHERE issueid = #issueid AND customfieldid = 99) PRINT CONVERT(NVARCHAR, #issueid) + ': ' + #domain It outputs the result as expected: 4850: www.domain.com When I have the same query in a trigger, it inserts the #issueid value correctly in the first column, but NULL in place of #section_name in the 2nd column: CREATE TRIGGER trigger_website_sections ON gemini_issues AFTER INSERT AS BEGIN SET NOCOUNT ON; IF (SELECT issuetypeid FROM inserted) = 58 BEGIN DECLARE #issueid numeric(10,0) DECLARE #domain nvarchar (255) SET #issueid = (SELECT issueid FROM inserted) SET #domain = (SELECT fielddata FROM customfielddata WHERE issueid = #issueid AND customfieldid = 99) INSERT INTO website_sections VALUES (#issueid, #domain); END END Can someone help figure out why?
Ok, after some more work I realised that because the row in customfielddata is created only after a row is created in issues (the 2nd is the primary table, and the 1st stores supplementary data for created records), the query on customfielddata will return NULL. And trying to concatenate a string with a NULL returns a NULL and that's what's inserted into the row. Mystery solved.
Isolating JOIN predicates from syscomments
In order to better understand all of the relationships in a database (physical and logical), I am looking to the stored procedures in order to extract the join predicates. I've got something I can work with, but its not complete. The goal is to have 3 columns in the result: The object name The first join predicate The second join predicate The join type (inner, right, left) declare #Schema varchar(50),#SearchString VARCHAR (10) set #SearchString = 'join'; set #Schema = 'dbo' declare #TextBuffer table ( SchemaName varchar(50) NOT NULL, ObjectName varchar(100) NOT NULL, Occurance int NOT NULL, Txt varchar(4000) NOT NULL, Colid int ) declare #Occurance table ( SchemaName varchar(50) NULL, ObjectName varchar(100) NULL, Occurance varchar(500) ) INSERT INTO #TextBuffer SELECT DISTINCT SCHEMA_NAME(o.schema_id), o.name, (LEN(text) - LEN(REPLACE(text, #SearchString, ''))) / LEN(#SearchString), [text], colid FROM syscomments AS c INNER JOIN sys.objects AS o ON c.id = o.[object_id] INNER JOIN sys.schemas AS s ON o.schema_id = s.schema_id WHERE text LIKE '%' + #SearchString + '%' AND SCHEMA_NAME(o.schema_id) = #Schema ORDER BY colid, 3 DESC; DECLARE #Txt varchar(4000), #ObjectName varchar(100), #Occ int, #SchemaName varchar(100) declare #count int, #position int set #count = 0 set #position = 0 DECLARE my_cursor CURSOR FAST_FORWARD FOR SELECT Txt,ObjectName, Occurance, SchemaName from #TextBuffer OPEN my_cursor FETCH NEXT FROM my_cursor INTO #Txt,#ObjectName,#Occ,#SchemaName WHILE ##FETCH_STATUS = 0 BEGIN set #count = #Occ while(#count > 0) begin set #position = charindex(#SearchString,#Txt) insert into #Occurance select #SchemaName, #ObjectName, cast(substring(#Txt, #position, len(#Txt)) as varchar(500)) set #Txt = substring(substring(#Txt,len(#SearchString),len(#Txt)), #position, len(#Txt)) set #count = #count -1 end FETCH NEXT FROM my_cursor INTO #Txt,#ObjectName,#Occ,#SchemaName END CLOSE my_cursor DEALLOCATE my_cursor select * from #Occurance