I'm currently experiencing the following problem.
If you have a look at the below test case:
declare #Count int
, #id int = 777
declare #table table
( id int identity primary key
, JCid int
, line int
, udf float )
insert into #table (jcid,line,udf)
values
(777,1,1),
(777,2,2.1),
(777,3,2.2),
(777,4,2),
(777,5,3)
select
#Count = count(left(L.udf,1))
from #table L
where L.jcid = #id
group by left(L.udf,1)
having count(left(L.udf,1))>1
select #Count
When I run this, I get the desired results of 3, however upon developing the below trigger, I can't get the count to work out correctly:
create trigger kv_trg_JobLineNumberUpdate_AW on _btblJCTxLines
after insert, update
as
declare #LineNum float
, #OldLine float
, #id int
, #Count int
, #Err nvarchar(500)
set #Err = '--------------------------';
set #Err = #Err + #Err + CHAR(10);
set #Err = #Err + CHAR(10);
set #Err = #Err + 'You are not allowed to change this Line Number!';
select
#LineNum = iLineID
, #OldLine = isnull(ufJCTxCMLineNumber,0)
, #id = iJCMasterID
from inserted
select
#Count = count(left(L.ufJCTxCMLineNumber,1))
from _btblJCTxLines L
join inserted i on left(L.ufJCTxCMLineNumber,1) = left(i.ufJCTxCMLineNumber,1)
where L.iJCMasterID = #id
group by left(L.ufJCTxCMLineNumber,1)
having count(left(L.ufJCTxCMLineNumber,1))>1
begin
if #OldLine = 0
begin
if #Count >= 2
begin
update _btblJCTxLines
set ufJCTxCMLineNumber = cast(#LineNum as varchar)+'.'+cast(#Count as varchar)
from _btblJCTxLines L
join inserted on L.idJCTxLines = inserted.idJCTxLines
end
else
begin
update _btblJCTxLines
set ufJCTxCMLineNumber = #LineNum
from _btblJCTxLines L
join inserted on L.idJCTxLines = inserted.idJCTxLines
end
end
else
begin
select
#OldLine = deleted.ufJCTxCMLineNumber
, #LineNum = inserted.ufJCTxCMLineNumber
from inserted, deleted
if (#OldLine <> #LineNum)
begin
raiserror(#Err, 16, 1)
rollback tran
return;
end
end
end
go
The ufJCTxCMLineNumber field is the duplicate number I'm looking for.
This triggers main purpose is to ensure that the ufJCTxCMLineNumber field never has duplicates.
What happens is, a user inserts a new line, when they add a new line above any current line, I want the ufJCTxCMLineNumber field to be updated to 3.1 depending on how many duplicates there is.
How would I go about getting the correct count?
Follow this link for Sample Data.
Related
Requirement: I have a table for storing queries (SQL programs). I need to search and find out in this table such queries which have hardcoded values for a particular column (name) as shown below:
SELECT
*
FROM TABLE1 AC
WHERE
AC.name = 'hardcoded_value1'
UNION
SELECT
*
FROM TABLE2 BC
WHERE BC.name = 'hardcoded_value2'
I have tried and done this using a function and it works fine. But the requirement has a constraint which doesn't allow to make use of any function or stored procedure.
Below is the function definition for reference:-
CREATE OR ALTER FUNCTION [dbo].[GetConstantValue](#QueryID INT)
RETURNS
#Constantvalue TABLE
(
name_ NVARCHAR(2000)
)
AS
BEGIN
Declare #Query NVARCHAR(max) = SELECT code FROM QUERY_TABLE WHERE ID = #QueryID
Declare #StartIndex int = 0,#EndIndex int = 0,#Count int = 0,#ConstStr nvarchar(max) = ''
WHILE #Count <= LEN(#Query)
BEGIN
IF SUBSTRING(#Query,#Count, 1) = CHAR(39)
BEGIN
IF #StartIndex <> 0
BEGIN
SET #ConstStr = #ConstStr + CASE WHEN LEN(#ConstStr)>0 THEN '|' ELSE '' END+ SUBSTRING(#Query,#StartIndex+1,#Count-(#StartIndex+1))
SET #StartIndex = 0
SET #EndIndex = 0
END
ELSE
IF SUBSTRING(#Query,#Count-20, 20) LIKE '%name%[=]%'
SET #StartIndex = #Count
END
SET #Count = #Count + 1
END
INSERT INTO #Constantvalue
SELECT Value FROM string_split(#ConstStr,'|')
RETURN
END
Please suggest me a way to achieve this in the main query itself without making any function calls
I have a large stored procedure which utilises a cursor. I want to put each instance of the cursor processing into a transaction, with a try-catch on the one insert, which on failure would terminate that transaction, back any inserts it did and then move to the next cursor instance. However, I am struggling with structuring this.
An example of what it looks like in brief is below. Basically I am trying to structure the try-catch for the patient insert to rollback the transaction and go onto the next cursor value when the patient insert fails.
Thanks
ALTER procedure [dbo].[Import_Archive_Record]
#PatientNumber varchar(10),
#PracticeId int
as
begin
DECLARE csr1 CURSOR for
select PatientNumber from ArchiveFull.dbo.ArchiveMasters where imported = 0 and PracticeId =
#PracticeId and PatientNumber = #PatientNumber
open csr1
fetch next from csr1 into #PatNo
while ##FETCH_STATUS = 0
begin
insert into Member....
select #memberId = SCOPE_IDENTITY()
print 'new member ' + cast(#memberId as varchar(10))
--insert patient
BEGIN TRY
select #initials = PatientInitials ,#surname = PatientSurname ,#name = PatientFirstname,
#DateOfBirth = DOBStr,#PatientCentury = DOBCen
from ArchiveFull.dbo.ArchiveMasters
where ArchiveFull.dbo.ArchiveMasters.PatientNumber = #PatNo
and imported = 0
and PracticeId = #PracticeId
set #patientID = null
select #patientID = id from Patient
where Initials = #initials
and Surname = #surname
and Name = #name
and MemberId = #memberId
print 'patientid ' + cast(#patientID as varchar(10))
set #DOB = dbo.getVisitdate(#PatientCentury,#DateOfBirth)
if #patientID is null
begin
insert into Patient(Name, Surname,Initials,MemberId,PostalSuburb,PostalCity,PostalCode,PostBox,Gender, DateofBirth,IDNumber,DependentCode,RelationToMember,AlternativesRelation,EMailAddress,CellPhone,Title)
select PatientFirstname,PatientSurname, coalesce(PatientInitials,'.'),#memberId,PatientAddress1, PatientAddress2, PatientAddress3,PatientAddress4,Gender,#DOB,PatientIDNumber,1,1,0,PatientEmail, CellNumber,PatientTitle
from ArchiveFull.dbo.ArchiveMasters
where PatientNumber = #PatNo
and imported = 0
END TRY
BEGIN CATCH
END CATCH
select #patientID = SCOPE_IDENTITY()
print 'new patientid ' + cast(#patientID as varchar(10))
end
set #BranchId = (select top 1 id from Branch where practiceid = #practiceId and ModalityRooms like concat('%', #BranchCode,'%'))
set #visitId = null
select #visitId = id from Visit
where BookingNumber = #PatNo
and BranchId = #BranchId
if #visitId is null
begin
declare #visitDate datetime
declare #century int
declare #date int
declare #DoctorCode nvarchar (max)
declare #DoctorSurname nvarchar (max)
declare #wca bit
select #century = Century, #date = ExamDateStr, #DoctorCode = RefDocCode, #DoctorSurname = RefDoc, #wca=WCA
from ArchiveFull.dbo.ArchiveMasters
where ArchiveFull.dbo.ArchiveMasters.PatientNumber = #PatNo
and imported = 0
and PracticeId = #PracticeId
update testlist
set century = #century, examdate = #date
where patno = #PatNo
set #visitDate = isnull(dbo.getVisitdate(#century,#date),'19000101')
set #DoctorId = null
set #DoctorId = dbo.getDoctorIdRadmin(#DoctorCode,#practiceId)
insert into Visit(Date,EndMonth, EndYear,NewBorn,HospitalClaim,WCA,WorkersComp,RAF,RoadAccidentFund,Examined,Booking,BookingNumber,PatientId,Notes,PreAuthorise,PreAuthNumber,BranchId,DoctorId, Receipted, ArchiveId)
select #visitDate, MONTH(#visitDate), YEAR(#visitdate) ,0,0,0,'',0,'',1,1,#PatNo,#patientID,'',0,AUTHNO,#BranchId,#DoctorId, 0, #archiveid
from ArchiveFull.dbo.ArchiveMasters
where ArchiveFull.dbo.ArchiveMasters.PatientNumber = #PatNo
and imported = 0
and PracticeId = #PracticeId
fetch next from csr1 into #PatNo
end
close csr1
deallocate csr1
I'm inserting (or trying to) one record into a table using the following trigger:
create trigger kv_trg_AssetAdjustment_AW
on _btblInvoiceLines --select * from _btblInvoiceLines
with encryption
after insert, update
as
if (select trigger_nestlevel(object_id('kv_trg_AssetAdjustment_AW'))) > 1
return
begin
declare #Asset varchar(40)
, #Desc varchar(100)
, #AssetValue float
, #Price float
, #Qty float
, #Code varchar(100)
, #Valid int
, #Exists int
, #SL int
, #NextNum int
, #Variable varchar(100)
, #NewCode varchar(100)
, #Err nvarchar(500)
select #Err = '--------------------------';
select #Err = #Err + #Err + CHAR(10);
select #Err = #Err + CHAR(10);
select #Err = #Err + 'Please specify a hyphen ("-") between Item Code & Description in the Description!';
if exists(select cDescription from inserted where cDescription like '%-%')
select #Valid = 1
else
begin
raiserror(#Err, 16, 1)
return;
end
select
#Asset = ulIDPOrdTxGLVAT
, #Code = LEFT(cDescription, CHARINDEX('-', cDescription) - 1)
, #Desc = REPLACE(SUBSTRING(cDescription, CHARINDEX('-', cDescription), LEN(cDescription)), '-', '')
, #AssetValue = fQuantityLineTotExcl
, #Qty = fQuantity
from inserted
if exists(select Code from StkItem where Code = #Code)
select #Exists = 1
else
select #Exists = 0
select #Variable = (select substring(#Code,1,len(#Code)-1))
select #NextNum = (select max(RIGHT(#Code,1))+1 from StkItem where Code like (#Variable + '%'))
select #NewCode = substring(#Code,1,len(#Code)-1) + cast(#NextNum as varchar)
begin
if (#Asset = 'Asset')
begin
if (#Exists = 0)
begin
insert into StkItem (
Code
, cSimpleCode
, Description_1
, Description_2
, TTI
, TTC
, TTG
, TTR
, WhseItem
, ubIIAsset
)
select #Code
, #Code
, #Desc
, #AssetValue
, 1
, 1
, 1
, 1
, 1
, 1
end
else
begin
insert into StkItem (
Code
, cSimpleCode
, Description_1
, Description_2
, TTI
, TTC
, TTG
, TTR
, WhseItem
, ubIIAsset
)
select #NewCode
, #NewCode
, #Desc
, #AssetValue
, 1
, 1
, 1
, 1
, 1
, 1
end
end
begin
update _btblInvoiceLines
set ufIDPOrdTxGLAssetValue = #AssetValue
from _btblInvoiceLines L
join inserted on L.idInvoiceLines = inserted.idInvoiceLines
end
end
END;
go
The record I'm inserting is into StkItem.
On this table I have a second trigger which fires after insert.
This trigger links this record (Stock Item) to all warehouses.
When I run these triggers separately, they work, but they do not want to work together.
I did notice that Trigger one adds more than one item, which I'm not sure if that is what is causing the problem.
Check code for second trigger:
set ansi_nulls on
go
set quoted_identifier on
go
set nocount on
go
create trigger kv_trg_LinkAssetToAllWhses_AW on StkItem
with encryption
after insert, update
as
if trigger_nestlevel() > 5
return
begin
declare #SL int
, #Asset int
, #Loop int
, #sqlCommand nvarchar(1000)
declare #WHs table
(
ID int identity primary key,
WhseID int
)
insert into #WHs (WhseID)
select WhseLink from WhseMst
order by WhseLink
select #SL = StockLink
, #Asset = ubIIAsset
from inserted
if (#Asset = 1)
begin
select #Loop = min(ID) FROM #WHs
while #Loop IS NOT NULL
begin
set #sqlCommand = 'exec _bspWhUtilLinkStkToWH;1 '+cast(#SL as varchar)+','+cast((select WhseID from #WHs where ID = #Loop) as varchar)+',0,0,1'
exec(#sqlCommand)
select #Loop = min(ID) FROM #WHs where ID>#Loop
end
end
end
go
I've searched all over the internet for a solution, but couldn't find anything pertaining to my exact problem.
I managed to narrow my problem down to the second trigger.
However, the second trigger executes a stored procedure which I did not develop.
Is there a problem with my second trigger or is it the stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[_bspWhUtilLinkStkToWH] #StockID int, #WhseID int, #IsDefaultWH bit, #AllowNegative bit, #iBranchID int = 0
AS
Set nocount on
Begin tran
Declare #SPError int
if (not exists (select * from WhseStk where WHWhseID=#WhseID and WHStockLink=#StockID)) begin
--Add to WhseStk
insert into WhseStk (WHWhseID, WHStockLink, bWHAllowNegStock, WhseStk_iBranchID)
values (#WhseID, #StockID, #AllowNegative, #iBranchID)
set #SPError = ##ERROR
if #SPError <> 0 goto AbortTran
if ((select top 1 bCostPerWarehouse from stdftbl where IsNull(StDfTbl_iBranchID,0)=0) = 1) begin
exec _espPriceUtilGetItemDef #StockId, #WhseID
end
end
goto CommitTran
AbortTran:
rollback tran
RAISERROR (#SPError, 16, 1)
return #SPError
CommitTran:
commit tran
return 0
GO
Thanks for your assistance so far.
What is wrong with this code.
If i type like this
Declare tmp as CURSOR FOR
Select i.ID from Inserted
OPEN tmp
Or if i type
Declare tmp as CURSOR FOR
Select i.ID from Deleted
OPEN tmp
Works like a charm but
Is there any way i can write something like this
if #operation <> 3
set #tmp = 'SELECT i.id FROM inserted i '
else
set #tmp =' SELECT i.id FROM deleted i '
DECLARE tmpUpit CURSOR FOR
#tmp
OPEN tmpUpit
Edit :
CREATE TRIGGER [dbo].[ax_Triger] ON [dbo].[extraTable]
FOR INSERT, UPDATE, DELETE AS
SET NOCOUNT ON;
--Capture the Operation (Inserted, Deleted Or Updated)
DECLARE #operation int
DECLARE #Count AS INT
SET #operation = 1
SELECT #Count = COUNT(*)
FROM DELETED
IF #Count > 0
BEGIN
SET #operation = 3
SELECT #Count = COUNT(*)
FROM INSERTED
IF #Count > 0
SET #operation = 2
END
DECLARE tmpUpit CURSOR FOR
SELECT i.id FROM inserted i
OPEN tmpUpit
FETCH NEXT FROM tmpUpit
into #ID WHILE ##fetch_status = 0
begin If Not exists
(SELECT * FROM mytable
where (Operation=3 OR (Operation=1 AND ID=#ID)) AND Status = 0 AND Tablename ='extraTable')
begin INSERT INTO
mytable ([Field1], [Field2],
[ID], [Tablename], [Operation], [Time12], [Status])
VALUES (#Field1, #Field2, #ID, 'extraTable', #operation,GETDATE(),0)
DELETE FROM mytable
WHERE [Field1]=#Field1 And [Field2]=#Field2 And [ID]=#ID And [Tablename]='extraTable'
AND [Operation] = 4 AND [Status] = 0
End
FETCH NEXT FROM tmpUpit into #ID
End CLOSE tmpUpit DEALLOCATE tmpUpit end
i need to insert the value from one table to another depending about the status Inserted/updated/deleted
This is completely untested since the table structures posted did not match the posted trigger code. This should at least demonstrate how you can rethink about this as set based logic instead of row by agonizing row.
CREATE TRIGGER [dbo].[Trigger212] ON [dbo].[Towns]
FOR INSERT, UPDATE, DELETE AS
BEGIN
SET NOCOUNT ON;
DECLARE #operation int
DECLARE #Variable1 nvarchar(8) = 'Woof'
DECLARE #Variable2 nvarchar(4) = 'Foof'
--Capture the Operation (Inserted, Deleted Or Updated)
IF EXISTS(SELECT * FROM inserted) AND NOT EXISTS (SELECT * FROM deleted)
SET #operation = 1 --Insert
ELSE
IF EXISTS(SELECT * FROM inserted) AND EXISTS (SELECT * FROM deleted)
SET #operation = 2 --update
ELSE
SET #operation = 3 -- DELETE
INSERT Requests
(
Field1
, Field2
, ID
, TableName
, Operation
, TimeU
, Status
)
SELECT 'Woof'
, 'Foof'
, i.ID
, 'Towns'
, #operation
, GETDATE()
, 0
FROM inserted i
LEFT JOIN Requests r on r.ID = i.ID
AND r.Operation = 3
OR (r.Operation = 1 and r.ID = i.ID)
AND r.Status = 0
AND r.TableName = 'Towns'
WHERE r.ID IS NULL
DELETE r
FROM Requests r
JOIN inserted i on i.Field1 = r.Field1
AND i.Field2 = r.Field2
AND i.ID = r.ID
AND i.Operation <> #operation
WHERE r.TableName = 'Towns'
AND r.Status = 0
END
In general I think triggers should be avoided but they have their place. When triggers are appropriate I am generally not a big fan of doing all three operations. Over time it gets really messy because invariably you need to do different logic for the different operations. Splitting them into three triggers makes this eventuality a lot less painful for maintenance.
I need a help in generating SQL result based on a column value to calculate per day amount.
I have a SQL like below.
select guid, reccharge, dayCareDaysCharged, dayCareHoursPerDay, RATE from tableA.
Here if reccharge = 0 (weekly) then the result should have 7 rows with RATE as RATE/7 for each row (per day amount);
if reccharge = 1 (monthly) then the result should have 30 rows with RATE as RATE/30 for each row;
if reccharge = 2 (yearly) then the result should have 365 rows with RATE as RATE/365 for each row;
if reccharge = 3 (hourly) then there should be a row as calculate it for a day;
How can I achieve this. Please help.
The question seems a little strange to me, but if I've followed it correctly then maybe this;
CREATE TABLE [#temp1] (reccharge tinyint,rdays smallint)
GO
declare #rcount smallint
set #rcount=0
while #rcount<7
begin
set #rcount=#rcount+1
insert #temp1 values (0,7)
end
set #rcount=0
while #rcount<30
begin
set #rcount=#rcount+1
insert #temp1 values (1,30)
end
set #rcount=0
while #rcount<365
begin
set #rcount=#rcount+1
insert #temp1 values (2,365)
end
insert #temp1 values (3,1)
GO
select t1.[guid], t1.reccharge, t1.dayCareDaysCharged, t1.dayCareHoursPerDay, t1.RATE/t2.rdays as RATE from tableA t1
inner join #temp1 t2 on t1.reccharge=t2.reccharge
order by t1.[guid]
I have not idea to do it in single query, but you can do it by using CURSOR as like below :
declare #reccharge int
declare #count int
declare #i int
declare #strSQL nvarchar(max) = 'select 1, 1 where 1 <> 1'
declare CurTest cursor for select reccharge from test
open CurTest
fetch next from CurTest into #reccharge
while ##fetch_status = 0
begin
set #i = 0;
select #count = case when #reccharge = 0 then 7 when #reccharge = 1 then 30 when #reccharge = 2 then 365 else 1 end
while #i < #count
begin
set #strSQL = #strSQL + ' union all select reccharge, Rate/' + cast(#count as varchar(10)) + ' from test where reccharge = ' + cast(#reccharge as varchar(10))
set #i = #i + 1;
end
fetch next from CurTest into #reccharge
end
close CurTest
deallocate CurTest
exec(#strSQL)