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