Time slots adding through trigger in SQL Server - sql-server

I am trying to have the trigger to add time slots in timeslots table each time the doctor insert a record of his availability in the availability table.
I wrote the trigger, it saved. but when I insert a record into availability, the trigger seems not triggered, yet I do not have any error message.
Can somebody help me? Badly needed.
Here is the code for trigger
ALTER TRIGGER [dbo].[trigger_addSlots]
ON [dbo].[availability]
FOR INSERT AS
BEGIN
DECLARE #AvailabilityId INT
DECLARE #SlotStart DATETIME
DECLARE #SlotEnd DATETIME
DECLARE #NumberOfSlots INT
DECLARE #Duration INT
DECLARE #SlotDoctorId INT
DECLARE #i INT
SELECT #AvailabilityId = Id FROM inserted
SELECT #SlotDoctorId = DoctorId FROM inserted
SELECT #SlotStart = AvailableFrom FROM inserted
SELECT #SlotEnd = AvailableTo FROM inserted
SELECT #Duration = AppointmentDuration FROM inserted
SET #NumberOfSlots = CONVERT(INT, (#SlotEnd - #SlotStart)) / #Duration
SET #i = 0;
WHILE #i < #NumberOfSlots
BEGIN
INSERT INTO timeslots(AvailabilityId, SlotStart, SlotEnd, SlotDoctorId, IsAvailable)
VALUES (#AvailabilityId, #SlotStart, #SlotEnd, #SlotDoctorId, 1)
SET #SlotStart = #SlotEnd
SET #i = #i + 1
END
END

Related

delete in small chunks from cursor data - T-SQL stored Procedure

i have written this t-sql stored procedure.
This is working fine , but since this stored procedure will be used to delete a lot of data (for example 1M to 2M) , I think, this can cause some locks in the table, or cause some db performance etc. So I am thinking, if we delete in batch for example at a time delete 1000 records. I am not totally sure about how to do this without cause any issue in db.
ALTER PROCEDURE [schema].[purge_data] #count INT---(count input can be in millions)
AS
DECLARE #p_number VARCHAR(22)
,#p_r_number VARCHAR(5)
DECLARE data_cursor CURSOR
FOR
SELECT TOP (#count) JRC_policy_number
,jrc_part_range_nbr
FROM [staging].[test].[p_location]
WHERE JRC_POLICY_TERM_DT < CAST('19950101 00:00:00.000' AS DATETIME)
AND jrc_policy_status = 'T'
OPEN data_cursor
FETCH NEXT
FROM data_cursor
INTO #p_number
,#p_r_number
WHILE ##FETCH_STATUS = 0
BEGIN
DELETE
FROM [staging].[test].[p_location]
WHERE JRC_policy_number = #p_number
AND jrc_part_range_nbr = #p_r_number
FETCH NEXT
FROM data_cursor
INTO #p_number
,#p_r_number
END
CLOSE data_cursor
DEALLOCATE data_cursor
Edit :
I had already tried without cursor - direct delete query like below.
DELETE TOP (1000) FROM [MyTab] WHERE YourConditions
It was very fast , it took 34 seconds to delete 1M records, but , during the 34 seconds, the table was locked completely. In production p_locator table is being used 24/7 , and being used by a very critical application, which expects response time in milliseconds, our purge script should not impact the the main application in any way. that's why I have chosen this cursor approach. pls guide
With some of your references I've written the below stored proc. Ofcourse there will be ALOT of scope for improvements. Pls share.
ALTER PROCEDURE [dbo].[purge_data] #count INT
AS
DECLARE #iteration INT
,#remainder INT
,#current_count INT
BEGIN
SELECT #current_count = count(*)
FROM PROD_TBL
WHERE JRC_POLICY_TERM_DT < CAST('19950101 00:00:00.000' AS DATETIME)
AND JRC_POLICY_STATUS = 'T'
AND JRC_PLCY_ADMIN_SYS_CD = 'X'
IF (#current_count < #count)
BEGIN
SET #count = #current_count
END
SET #iteration = #count / 10000
SET #remainder = #count % 10000
WHILE (#iteration > 0)
BEGIN
DELETE
FROM PROD_TBL
FROM (
SELECT TOP 10000 JRC_POLICY_NUMBER
,JRC_PART_RANGE_NBR
,JRC_PLCY_ADMIN_SYS_CD
FROM PROD_TBL
WHERE JRC_POLICY_TERM_DT < CAST('19950101 00:00:00.000' AS DATETIME)
AND JRC_POLICY_STATUS = 'T'
AND JRC_PLCY_ADMIN_SYS_CD = 'X'
) pol_locator_tbl
WHERE PROD_TBL.JRC_POLICY_NUMBER = pol_locator_tbl.JRC_POLICY_NUMBER
AND PROD_TBL.JRC_PART_RANGE_NBR = pol_locator_tbl.JRC_PART_RANGE_NBR
AND PROD_TBL.JRC_PLCY_ADMIN_SYS_CD=pol_locator_tbl.JRC_PLCY_ADMIN_SYS_CD
SET #iteration = #iteration - 1
END
IF (#remainder > 0)
BEGIN
DELETE
FROM PROD_TBL
FROM (
SELECT TOP (#remainder) JRC_POLICY_NUMBER
,JRC_PART_RANGE_NBR
,JRC_PLCY_ADMIN_SYS_CD
FROM PROD_TBL
WHERE JRC_POLICY_TERM_DT < CAST('19950101 00:00:00.000' AS DATETIME)
AND JRC_POLICY_STATUS = 'T'
AND JRC_PLCY_ADMIN_SYS_CD = 'X'
) pol_locator_tbl
WHERE PROD_TBL.JRC_POLICY_NUMBER = pol_locator_tbl.JRC_POLICY_NUMBER
AND PROD_TBL.JRC_PART_RANGE_NBR = pol_locator_tbl.JRC_PART_RANGE_NBR
AND PROD_TBL.JRC_PLCY_ADMIN_SYS_CD=pol_locator_tbl.JRC_PLCY_ADMIN_SYS_CD
END
END
END

How to get and use the value returned by a stored procedure to a INSERT INTO... SELECT... statement

I am just new in SQL language and still studying it. I'm having hard time looking for answer on how can I use the stored procedure and insert value into a table.
I have this stored procedure:
CREATE PROCEDURE TestID
AS
SET NOCOUNT ON;
BEGIN
DECLARE #NewID VARCHAR(30),
#GenID INT,
#BrgyCode VARCHAR(5) = '23548'
SET #GenID = (SELECT TOP (1) NextID
FROM dbo.RandomIDs
WHERE IsUsed = 0
ORDER BY RowNumber)
SET #NewID = #BrgyCode + '-' + CAST(#GenID AS VARCHAR (30))
UPDATE dbo.RandomIDs
SET dbo.RandomIDs.IsUsed = 1
WHERE dbo.RandomIDs.NextID = #GenID
SELECT #NewID
END;
and what I'm trying to do is this:
INSERT INTO dbo.Residents([ResidentID], NewResidentID, [ResLogdate],
...
SELECT
[ResidentID],
EXEC TestID ,
[ResLogdate],
....
FROM
source.dbo.Resident;
There is a table dbo.RandomIDs containing random 6 digit non repeating numbers where I'm pulling out the value via the stored procedure and updating the IsUsed column of the table to 1. I'm transferring data from one database to another database and doing some processing on the data while transferring. Part of the processing is generating a new ID with the required format.
But I can't get it to work Sad I've been searching the net for hours now but I'm not getting the information that I need and that the reason for my writing. I hope someone could help me with this.
Thanks,
Darren
your question is little bit confusing, because you have not explained what you want to do. As i got your question, you want to fetch random id from randomids table and after performed some processing on nextid you want to insert it into resident table [newresidentid] and end of the procedure you fetch data from resident table. if i get anything wrong feel free to ask me.
your procedure solution is following.
CREATE PROCEDURE [TestId]
AS
SET NOCOUNT ON;
BEGIN
DECLARE #NEWID NVARCHAR(30)
DECLARE #GENID BIGINT
DECLARE #BRGYCODE VARCHAR(5) = '23548'
DECLARE #COUNT INTEGER
DECLARE #ERR NVARCHAR(20) = 'NO IDS IN RANDOM ID'
SET #COUNT = (SELECT COUNT(NEXTID) FROM RandomIds WHERE [IsUsed] = 0)
SET #GENID = (SELECT TOP(1) [NEXTID] FROM RandomIds WHERE [IsUsed] = 0 ORDER BY [ID] ASC)
--SELECT #GENID AS ID
IF #COUNT = 0
BEGIN
SELECT #ERR AS ERROR
END
ELSE
BEGIN
SET #NEWID = #BRGYCODE + '-' + CAST(#GENID AS varchar(30))
UPDATE RandomIds SET [IsUsed] = 1 WHERE [NextId] = #GENID
INSERT INTO Residents ([NewResidentId] , [ResLogDate] ) VALUES (#NEWID , GETDATE())
SELECT * FROM Residents
END
END
this procedure will fetch data from your randomids table and perform some processing on nextid than after it directs insert it into resident table and if you want to insert some data through user you can use parameter after declaring procedure name
E.G
CREATE PROCEDURE [TESTID]
#PARAM1 DATATYPE,
#PARAM2 DATATYPE
AS
BEGIN
END
I'm not convinced that your requirement is a good one but here is a way to do it.
Bear in mind that concurrent sessions will not be able to read your update until it is committed so you have to kind of "lock" the update so you will get a block until you're going to commit or rollback. This is rubbish for concurrency, but that's a side effect of this requirement.
declare #cap table ( capturedValue int);
declare #GENID int;
update top (1) RandomIds set IsUsed=1
output inserted.NextID into #cap
where IsUsed=0;
set #GENID =(select max( capturedValue) from #cap )
A better way would be to use an IDENTITY or SEQUENCE to solve your problem. This would leave gaps but help concurrency.

SQL Server if statement does not execute as expected

I am trying to use the following stored procedure but there are some instances WHERE only the incremental happens AND the code does not run. What I need is that, when the program enters the IF statement, either it should run both the statements or None.
Stored procedure goes like this:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spflpunch]
AS
BEGIN
DECLARE #id NUMERIC(18,0)
DECLARE #studname NVARCHAR(50)
DECLARE #punchtime DATETIME
DECLARE #samedaycount NUMERIC(2)
SELECT #id = (MAX(lastid)) FROM [smartswype].[dbo].[read]
PRINT #id
SELECT #studname = studname
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE id =#id
PRINT #studname
SELECT #punchtime = punchtime
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE id = #id
PRINT #punchtime
--SELECT #punchvarchar = CONVERT(VARCHAR(10),#punchtime, 103) + ' ' + CONVERT(VARCHAR(5), #punchtime, 14)
IF #id = (SELECT MAX(id) FROM [SSWYPE_WEBDB].[dbo].[attdview])
BEGIN
SELECT #samedaycount = COUNT(*)
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE (studname = #studname
AND CONVERT(DATE, punchtime) = CONVERT(DATE, #punchtime)) -- If firstpunch = 1 then it is the first punch
PRINT #samedaycount
IF #samedaycount =1
BEGIN
INSERT INTO [smartswype].[dbo].[firstlastpunch] ([studname], [DATE], [punch1], [punch2])
VALUES(#studname, CONVERT(DATE, #punchtime), #punchtime, NULL);
UPDATE [smartswype].[dbo].[read]
SET lastid = #id + 1;
END
ELSE IF (#samedaycount > 1)
BEGIN
UPDATE [smartswype].[dbo].[firstlastpunch]
SET punch2 = #punchtime
WHERE (studname = #studname AND DATE = CONVERT(DATE, #punchtime));
UPDATE [smartswype].[dbo].[read]
SET lastid = #id + 1;
END
END
END
If you want to ensure that both or none of the statements run, you should wrap the contents of the if statement in a transaction.
By wrapping it in a transaction, you can ensure that if one statement fails, that the other statement will not run.
Here is a link to the docs on transactions in SQL Server
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/commit-transaction-transact-sql

SQL Server 2012 Trigger

Hey guys thank you in advance for any help,
I have this trigger in my SQL Server 2012 database
USE Teste_TextMining
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE dbo.textos
SET tag = UPPER(#tag)
WHERE ID_texto = #ID
END
BEGIN
UPDATE dbo.textos
SET data = GETDATE()
WHERE ID_texto = #ID
END
GO
And as you can see it should update 2 values the "tag" row and the "data" row once something is inserted in the table, however its only updating the "data" row.
If i just select this piece of code and run/debug it, it actually updates both rows, any idea why this is hapening ?
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE dbo.textos
SET tag = UPPER(#tag)
WHERE ID_texto = #ID
END
BEGIN
UPDATE dbo.textos
SET data = GETDATE()
WHERE ID_texto = #ID
END
Once again thank you in advance for your help and time.
I assume that you are performing the following query simply to get the inserted row:
SELECT MAX(ID_texto) FROM dbo.textos
That won't work, as others have pointed out. If you insert more than one row at once, only the last in the set will be modified by the trigger.
Do a JOIN on the INSERTED table to get the new rows, then another JOIN on semantickeyphrasetable(textos, *) to get the tag values. Something like this:
USE Teste_TextMining
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
BEGIN
UPDATE T
SET tag = UPPER(K.keyphrase), data = GETDATE()
FROM dbo.textos T
JOIN INSERTED ON INSERTED.ID_texto = T.ID_texto
LEFT JOIN (
SELECT TOP 1 document_key, keyphrase
FROM semantickeyphrasetable(textos, *)
) K ON K.document_key=T.ID_texto
END
GO
Triggers will basically trigger once for each batch operation, so you should perform your logic based on this reality. This is also in SQL spirit, which favors (read as performs better) set based operations.
All inserted items are stored into a special table, called inserted, so you should join with this table to know what are the exact records that were touched:
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
BEGIN
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE Dest
SET tag = UPPER(#tag)
FROM dbo.textos Dest
JOIN inserted I ON I.ID_texto = Dest.ID_texto
WHERE ID_texto = #ID
END
BEGIN
UPDATE Dest
SET data = GETDATE()
FROM dbo.textos Dest
JOIN inserted I ON I.ID_texto = Dest.ID_texto
WHERE ID_texto = #ID
END
END
The above is not tested, but should help you get an idea on how to proceed to actually update records that were inserted.
Did this answer ever get solved?
If not, why not just add both updates in one line instead of having 2 BEGIN...END blocks?
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
BEGIN
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE Dest
SET tag = UPPER(#tag), data = GETDATE()
FROM dbo.textos Dest
JOIN inserted I ON I.ID_texto = Dest.ID_texto
WHERE ID_texto = #ID
END
END
Use the below code. In your case I think the trigger is firing before semantickeyphrasetable TABLE insertion done. So updating nothing in first begin as #tag is empty.
Its better to put the trigger in child table.(If we need to update Parent table with child table data.)
USE Teste_TextMining
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
DECLARE #ID INT
,#tag NVARCHAR(MAX)
SELECT #ID = ID_texto
FROM INSERTED
SET #tag = (
SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key = #ID
)
UPDATE dbo.textos
SET tag = UPPER(#tag)
,
SET data = GETDATE()
WHERE ID_texto = #ID
GO
Note: When multiple insertion done, it will fail.

Can I get the last inserted row that a trigger created, inside of a stored procedure?

I have a stored procedure that updates a record. Our DBA created a trigger that updates that row and deactivates the record. It then creates an identical record, but with an active flag and it receives a new auto generated PK. So it goes something like this:
PK=1, Active=1, Data='test' --> PK=1, Active=0, Data='test' --> PK=2, Active=1, Data='test2'
But in my stored procedure, which calls the update, I need to get the last row that the trigger inserted.
Is it possible?
Here is my update code:
UPDATE [OASIS].[dbo].[TT_PEQHeader]
SET
[LastUpdateDate] = GETDATE()
,[LastUpdateBy] =#intUserPK
,[ID] = #vchID
,[Description] = #vchDescription
,[CompletionRate] = #dcCompletionRate
,[IndustryExperiance] = #intIndustryExperiance
WHERE PEQHeaderPK= #intPEQHeaderPK
SELECT * FROM vw_TT_PEQHeader WHERE PEQHeaderPK = #intPEQHeaderPK
I'm currently getting the record based on the PK sent to the SP. That's what I need to change.
Here's the trigger code:
USE [OASIS]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[Update_TT_PEQHeader]
ON [dbo].[TT_PEQHeader]
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON;
Declare #dPEQHeaderPK AS INT
Declare #dLastUpdateDate AS DATETIME
Declare #dLastUpdateBy AS INT
Declare #dID AS VARCHAR(25)
Declare #dDescription AS VARCHAR(50)
Declare #dVersion AS INT
Declare #dPreviousVersionPK AS INT
Declare #dActive AS BIT
Declare #dCompletionRate AS DECIMAL(18,2)
Declare #dIndustryExperiance AS INT
Declare #NewPEQHeaderPK AS INT
SELECT
#dPEQHeaderPK =a.PEQHeaderPK,
#dLastUpdateDate = a.LastUpdateDate,
#dLastUpdateBy = a.LastUpdateBy,
#dID = a.ID,
#dDescription = a.Description,
#dVersion = a.Version,
#dPreviousVersionPK = a.PreviousVersionPK,
#dActive = a.Active,
#dCompletionRate = a.CompletionRate,
#dIndustryExperiance = a.IndustryExperiance
FROM INSERTED a
INNER JOIN deleted ON a.PEQHeaderPK = deleted.PEQHeaderPK
/*Deativate the old record*/
Update TT_PEQHeader SET Active = 0 where PEQHeaderPK = #dPEQHeaderPK
IF(#dActive = 1)
BEGIN
/*Copy and paste a new PEQH record*/
INSERT INTO TT_PEQHeader
SELECT GETDATE(),#dLastUpdateBy,GETDATE(),#dLastUpdateBy,#dID,#dDescription,#dVersion + 1,#dPEQHeaderPK,1,#dCompletionRate,#dIndustryExperiance
SELECT #NewPEQHeaderPK = SCOPE_IDENTITY()
/*Copy and paste a new batch of PEQD records*/
INSERT INTO TT_PEQDetail
SELECT GETDATE(),#dLastUpdateBy,GETDATE(),#dLastUpdateBy,#NewPEQHeaderPK,QuestionID,QuestionText FROM TT_PEQDetail WHERE PEQHeaderFK = #dPEQHeaderPK
END
END

Resources