SQL MERGE error? [duplicate] - sql

This question already has an answer here:
Msg 8672, Level 16, State 1, Line 1 The MERGE statement attempted to UPDATE or DELETE the same row more than once
(1 answer)
Closed 4 years ago.
Please see my below code - I am new to SQL and haven't seen this error before. Can someone advise as to where it is going wrong? The error I am getting is
(41669 row(s) affected) Msg 8672, Level 16, State 1, Line 41 The MERGE
statement attempted to UPDATE or DELETE the same row more than once.
This happens when a target row matches more than one source row. A
MERGE statement cannot UPDATE/DELETE the same row of the target table
multiple times. Refine the ON clause to ensure a target row matches at
most one source row, or use the GROUP BY clause to group the source
rows.
My code is below
DECLARE #FromDate DateTime = '31 jan 2018'
DECLARE #ToDate DateTime = '28 Feb 2018'
DECLARE #FromDate_In DateTime = #FromDate
DECLARE #ToDate_In DateTime = #ToDate
DECLARE #DirectDebit_In INT = 0
/**************************/
/* Agreement view */
/**************************/
SELECT
sag.[AgreementID]
,sca.CustomerID
,'Lost' AS [Type]
INTO #AgreementSet
FROM Money.dbo.[Fin_SS_TblAgreements] sag WITH (NOLOCK)
INNER JOIN Money.dbo.[Fin_SS_TblCustomersAgreements] [sca] WITH (NOLOCK) ON sca.DealID = sag.DealID AND sca.IsMasterCustomer = 1 AND sca.[SnapShot] = sag.[SnapShot]
INNER JOIN (
SELECT
sps.DealID
FROM Money.dbo.[Fin_SS_TblPaymentSchedule] sps WITH (NOLOCK, INDEX(IX_NC_Snapshot))
WHERE sps.[SnapShot] = #FromDate_In
GROUP BY sps.DealID
) sps ON sag.DealID = sps.DealID
WHERE sag.[SnapShot] = #FromDate_In
AND (sag.AgreementID IS NOT NULL)
AND ((sag.EndDate > sag.[SnapShot]) OR (sag.EndDate = sag.[SnapShot] AND sag.Autorenew = 1))
AND (sag.AgreementStartsOn <= sag.[SnapShot])
AND ( (#DirectDebit_In = 0 AND sag.ContractTypeID <> 3) OR (#DirectDebit_In = 1 AND sag.ContractTypeID = 3) OR (#DirectDebit_In = 3) )
DECLARE #MaxAgIDFrom INT
SELECT #MaxAgIDFrom = MAX(AgreementID) FROM Money.dbo.[Fin_SS_TblAgreements] WHERE [SnapShot] = #FromDate_In
DECLARE #MaxCIDFrom INT
SELECT #MaxCIDFrom = MAX(CustomerID) FROM #AgreementSet
MERGE INTO #AgreementSet L
USING (
SELECT
sag.[AgreementID]
,sca.CustomerID
,'New' AS [Type]
FROM Money.dbo.[Fin_SS_TblAgreements] sag WITH (NOLOCK)
INNER JOIN Money.dbo.[Fin_SS_TblCustomersAgreements] [sca] WITH (NOLOCK) ON sca.DealID = sag.DealID AND sca.IsMasterCustomer = 1 AND sca.[SnapShot] = sag.[SnapShot]
INNER JOIN (
SELECT
sps.DealID
FROM Money.dbo.[Fin_SS_TblPaymentSchedule] sps WITH (NOLOCK, INDEX(IX_NC_Snapshot))
WHERE sps.[SnapShot] = #ToDate_In
GROUP BY sps.DealID
) sps ON sag.DealID = sps.DealID
WHERE sag.[SnapShot] = #ToDate_In
AND (sag.AgreementID IS NOT NULL)
AND ((sag.EndDate > sag.[SnapShot]) OR (sag.EndDate = sag.[SnapShot] AND sag.Autorenew = 1))
AND (sag.AgreementStartsOn <= sag.[SnapShot])
AND ( (#DirectDebit_In = 0 AND sag.ContractTypeID <> 3) OR (#DirectDebit_In = 1 AND sag.ContractTypeID = 3) OR (#DirectDebit_In = 3) )
) N
ON L.AgreementID = N.AgreementID
WHEN MATCHED THEN
UPDATE SET [Type] =
CASE WHEN L.CustomerID = n.CustomerID THEN 'B/F'
ELSE 'Swap'
END
WHEN NOT MATCHED THEN
INSERT (AgreementID, CustomerID, [Type])
VALUES (n.AgreementID, n.CustomerID, n.[Type])

We get this very often.
This happens because of unique column that is being used in more than one row.
In your case this may be because of same agreementid for two or more different customers.
Check the data again and perform the same operation again.

Related

SQL Server Date Comparison issue

I am trying to flag a field in a different table whenever two dates do not have the right relationship. However, All dates in the dataset should not flag anything(should be 0 instead of 1), but they all flag. Could it be an issue with the date format changing during the query? Really stuck here
Example output
UPDATE Theatre_DQ_03_Integrity_CASES
SET AnaesToTheatreFlag = 1, TimeErrorFlag = 1
FROM Theatre_Cases_Landing a
INNER JOIN
(
SELECT Case_ID
FROM Theatre_Cases_Landing
WHERE (CaseCancelled IS NULL or CaseCancelled = 'N') AND (CONVERT(datetime,Anaesthetic_Start_DateTime) > CONVERT(datetime,In_Theatre_DateTime))
AND Anaesthetic_Start_DateTime IS NOT NULL AND In_Theatre_DateTime IS NOT NULL
) b
ON a.Case_ID = b.Case_ID
declare #var1 as datetime2 = '2019-09-04 11:12:00.000'
declare #var2 as datetime2 = '2019-09-04 11:13:00.000'
if #var1 < #var2 PRINT('TRUE')
You need to correlate rows to be updated with the rows from the other table. Otherwise, every row in the target will be updated.
I don't see a need to self-join Theatre_Cases_Landing. Below is an untested version with the correlation.
UPDATE target
SET AnaesToTheatreFlag = 1, TimeErrorFlag = 1
FROM Theatre_DQ_03_Integrity_CASES AS target
JOIN Theatre_Cases_Landing AS a ON a.Case_ID = target.Case_ID
WHERE
(a.CaseCancelled IS NULL or a.CaseCancelled = 'N')
AND CONVERT(datetime,a.Anaesthetic_Start_DateTime) > CONVERT(datetime,a.In_Theatre_DateTime)
AND a.Anaesthetic_Start_DateTime IS NOT NULL
AND a.In_Theatre_DateTime IS NOT NULL;

Understanding a SQL Statement

I'm trying to modify a stored procedure on a Microsoft SQL server that is used to get data for a SSRS table. It currently filters by a few parameters, one of them "Analyst" but I would like for the query to return the analyst as well to the report so if you leave the parameter empty it would you could still see what analyst was assigned the ticket
This is the code used to find the analyst info, how can I edit it to allow me to return the Analyst display name as well?
LEFT OUTER JOIN(
SELECT
Analyst.UserName AS AnalystASURITE,
Analyst.DisplayName AS DisplayName,
Analyst.UserDimKey,
WIATUFact.WorkItemDimKey
FROM
dbo.UserDim Analyst
JOIN
dbo.WorkItemAssignedToUserFactvw WIATUFact
ON Analyst.UserDimKey = WIATUFact.WorkItemAssignedToUser_UserDimKey
WHERE WIATUFact.DeletedDate IS NULL -- We only need the information for the last analyst assigned.
GROUP BY WIATUFact.WorkItemDimKey, Analyst.UserName, Analyst.DisplayName, Analyst.UserDimKey, WIATUFact.CreatedDate
) AssignedAnalystInfo
ON AssignedAnalystInfo.WorkItemDimKey = WI.WorkItemDimKey
I added
Analyst = AssignedAnalystInfo.DisplayName,
to the top of my procedure and it was correct syntax but got this error
Column 'AssignedAnalystInfo.DisplayName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I can add the whole procedure if that is needed but it's pretty long.
USE [DWDataMart]
GO
/****** Object: StoredProcedure [dbo].[RTS_Report_IncidentManagement_GetIncidentMetricData2018] Script Date: 11/29/2018 2:30:26 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[RTS_Report_IncidentManagement_GetIncidentMetricData2018]
#StartDate datetime,
#EndDate datetime,
#LanguageCode nvarchar(max)= 'ENU',
#Department nvarchar(max) = '',
#Analyst nvarchar(max) = '',
#AffectedUser nvarchar(max) = '',
#DateFilter nvarchar(256) = 'CreatedOn',
#SupportGroups nvarchar(max) = -1,
#Priority nvarchar(max) = -1
AS
BEGIN
SET NOCOUNT ON
/* Adds a day to the End Date if it is set to midnight.
This is needed as the console picks midnight of the End Date which cuts off the last day.
Otherwise it simply leaves it as is.*/
If (#EndDate = cast(#EndDate as date))
SET #EndDate = DATEADD(DAY, 1, #EndDate)
DECLARE #Error int
DECLARE #ExecError int
DECLARE #tableDept TABLE (value nvarchar(256))
INSERT #tableDept (value)
SELECT * FROM dbo.fn_CSVToTableString(#Department)
DECLARE #tableAnalyst TABLE (value nvarchar(256))
INSERT #tableAnalyst(value)
SELECT * FROM dbo.fn_CSVToTableString(#Analyst)
DECLARE #tableAffectedUser TABLE (value nvarchar(256))
INSERT #tableAffectedUser(value)
SELECT * FROM dbo.fn_CSVToTableString(#AffectedUser)
DECLARE #tableSupportGroups TABLE (value nvarchar(256))
INSERT #tableSupportGroups (value)
SELECT * FROM dbo.fn_CSVToTableInt(#SupportGroups)
DECLARE #tablePriority TABLE (value nvarchar(256))
INSERT #tablePriority (value)
SELECT * FROM dbo.fn_CSVToTableInt(#Priority)
SELECT
--We need some datasets. This SP will pull each incident based on the parameters. How it is displayed
--depends on the report running this SP.
IncidentTitle = I.Title,
AffectedUser = AffectedUserInfo.DisplayName,
IncidentIR = I.Id,
AAnalyst = AssignedAnalystInfo.DisplayName,
IRCreatedDate = I.CreatedDate,
IRResolvedDate = I.ResolvedDate,
TimeToAssignment = CASE
WHEN
(
FirstAssignedDate.CreatedDate IS NOT NULL
AND
I.Priority > 3
)
THEN
DATEDIFF(MINUTE, I.CreatedDate, FirstAssignedDate.CreatedDate)
ELSE NULL
END,
TimeWorked = CASE
WHEN
(
(TotalBT.TimeWorked IS NOT NULL)
)
THEN
TotalBT.TimeWorked
ELSE NULL
END,
TimeToResolution = CASE
WHEN
(
(I.Status = 'IncidentStatusEnum.Resolved' OR I.Status = 'IncidentStatusEnum.Closed')
AND
(I.CreatedDate IS NOT NULL)
AND
(I.ResolvedDate IS NOT NULL)
AND
(I.Priority > 3)
)
THEN
DATEDIFF(MINUTE, I.CreatedDate, I.ResolvedDate) - dFact.PendingDuration
ELSE NULL
END,
-- Unseen stuff is selected and processed accordingly
IncidentDimKey = I.IncidentDimKey
FROM dbo.IncidentDim I
-- JOINS to other needed tables
-- Join the incident dimension to the workitem dimension.
INNER JOIN dbo.WorkItemDim WI
ON WI.EntityDimKey = I.EntityDimKey
--Join the AssignedTo fact table to the workitem table. We can use this to get information on the assigned
--analyst.
LEFT OUTER JOIN(
SELECT
Analyst.UserName AS AnalystASURITE,
Analyst.DisplayName AS DisplayName,
Analyst.UserDimKey,
WIATUFact.WorkItemDimKey
FROM
dbo.UserDim Analyst
JOIN
dbo.WorkItemAssignedToUserFactvw WIATUFact
ON Analyst.UserDimKey = WIATUFact.WorkItemAssignedToUser_UserDimKey
WHERE WIATUFact.DeletedDate IS NULL -- We only need the information for the last analyst assigned.
GROUP BY WIATUFact.WorkItemDimKey, Analyst.UserName, Analyst.DisplayName, Analyst.UserDimKey, WIATUFact.CreatedDate
) AssignedAnalystInfo
ON AssignedAnalystInfo.WorkItemDimKey = WI.WorkItemDimKey
--Join the Assigned To fact table so we can calculate the assignment times. Only need the first assignment information.
LEFT OUTER JOIN(
SELECT
WorkItemDimKey,
MIN(CreatedDate) AS CreatedDate
FROM
dbo.WorkItemAssignedToUserFactvw WIATUFact
GROUP BY WorkItemDimKey
) FirstAssignedDate
ON FirstAssignedDate.WorkItemDimKey = WI.WorkItemDimKey
--Start Total TimeWorked joins. We can pull time and sum per incident.
LEFT OUTER JOIN(
SELECT
SUM(BT.TimeInMinutes) AS TimeWorked,
WIBTFact.WorkItemDimKey
FROM
dbo.BillableTimeDim BT
JOIN
dbo.WorkItemHasBillableTimeFactvw WIBTFact
ON BT.BillableTimeDimKey = WIBTFact.WorkItemHasBillableTime_BillableTimeDimKey
GROUP BY WIBTFact.WorkItemDimKey
) TotalBT
ON TotalBT.WorkItemDimKey = WI.WorkItemDimKey
--Join the AffectedUser fact table to the workitem table. We need this so we have some information about
--the affeted user.
LEFT OUTER JOIN(
SELECT
UserName,
DisplayName,
Department =
CASE
WHEN(Department = '' OR Department IS NULL)
THEN 'Unknown'
ELSE Department
END,
WIAUFact.WorkItemDimKey
FROM UserDim AffectedUserInfo
JOIN dbo.WorkItemAffectedUserFactvw WIAUFact ON AffectedUserInfo.UserDimKey = WIAUFact.WorkItemAffectedUser_UserDimKey
AND
WIAUFact.DeletedDate IS NULL
GROUP BY WorkItemDimKey, CreatedDate, UserName, Department, DisplayName
) AS AffectedUserInfo
ON AffectedUserInfo.WorkItemDimKey = WI.WorkItemDimKey
--Next two JOIN needed so we can pull the name and enum values for the support groups.
LEFT OUTER JOIN dbo.IncidentTierQueues AS SupportGroupEnum
ON SupportGroupEnum.IncidentTierQueuesId = I.TierQueue_IncidentTierQueuesId
LEFT OUTER JOIN
dbo.DisplayStringDim SupportGroupDS
ON SupportGroupEnum.EnumTypeId=SupportGroupDS.BaseManagedEntityId
AND SupportGroupDS.LanguageCode = #LanguageCode
LEFT OUTER JOIN
(
SELECT
ActiveDuration = SUM(
CASE
WHEN statusEnum.ID = 'IncidentStatusEnum.Active'
THEN dFact.TotalTimeMeasure
ELSE 0
END
),
PendingDuration = SUM(
CASE
WHEN statusEnum.ID = 'IncidentStatusEnum.Active.Pending'
THEN dFact.TotalTimeMeasure
ELSE 0
END
),
dFact.IncidentDimKey
FROM
dbo.IncidentStatusDurationFactvw dFact
LEFT OUTER JOIN
dbo.IncidentStatus statusEnum
ON statusEnum.IncidentStatusId = dFact.IncidentStatusId
GROUP BY dfact.IncidentDimKey
) dFact
ON dFact.IncidentDimKey = I.IncidentDimKey
WHERE
(#StartDate <= #EndDate)
AND
I.CreatedDate >= #StartDate
AND
I.CreatedDate <= #EndDate
AND
(
(#DateFilter = 'ClosedOn' AND ((I.ClosedDate >= #StartDate) AND (I.ClosedDate < #EndDate))) OR
(#DateFilter = 'CreatedOn' AND ((I.CreatedDate >= #StartDate) AND (I.CreatedDate < #EndDate))) OR
(#DateFilter = 'ResolvedOn' AND ((I.ResolvedDate >= #StartDate) AND (I.ResolvedDate < #EndDate)))
)
AND
((-1 IN (Select value from #tableSupportGroups)) OR (CASE WHEN (SupportGroupEnum.IncidentTierQueuesId IS NULL) THEN '0' ELSE SupportGroupEnum.IncidentTierQueuesId END IN (SELECT value FROM #tableSupportGroups)))
AND
(('' IN (Select value from #tableDept)) OR (AffectedUserInfo.Department IN (Select value from #tableDept)))
AND
(('' IN (Select value from #tableAnalyst)) OR (AssignedAnalystInfo.AnalystASURITE IN(Select value from #tableAnalyst)))
AND
(('' IN (Select value from #tableAffectedUser)) OR (AffectedUserInfo.UserName IN(Select value from #tableAffectedUser)))
AND
((-1 IN (Select value from #tablePriority)) OR (I.Priority IN (Select value from #tablePriority)))
GROUP BY
I.Title,
I.Id,
I.CreatedDate,
I.ResolvedDate,
I.Priority,
I.Status,
I.IncidentDimKey,
TimeWorked,
AffectedUserInfo.DisplayName,
FirstAssignedDate.CreatedDate,
dFact.PendingDuration
SET #Error = ##ERROR
QuitError:
Return #Error
END

SQL How to count all remains for each date

I have the following SQL function
CREATE FUNCTION [dbo].[GetCardDepartRemains]
(
#CardId INT,
#DepartId INT,
#Date DATETIME = NULL,
#DocumentId INT = NULL
)
RETURNS INT
AS
BEGIN
DECLARE #Res INT
SELECT
#Res = ISNULL(SUM(CASE WHEN Operations.[Output] = 0 AND Operations.RecipientId = #DepartId THEN 1 ELSE -1 END), 0)
FROM dbo.Operations
WHERE Operations.CardId = #CardId
AND (Operations.[Output] = 0 AND Operations.RecipientId = #DepartId OR Operations.Input = 0 AND Operations.SenderId = #DepartId)
AND (#Date IS NULL OR Operations.[Date] <= #Date)
RETURN #Res
END
GO
It counts remains for certain product on certain department on certain date.
If it is less then zero it means something's wrong with database
Now I need to find all remains for each card, for each department for all dates in database where result is wrong.
Theoretically speaking we can fing this by calling this procedure in a query like this
SELECT DISTINCT Operations.[Date] as [Date],
Departments.Id as Depart,
Cards.Id as [Card],
[dbo].[GetCardDepartRemains] (Cards.Id, Departments.Id,Operations.[Date],NULL) as Res
FROM [jewellery].[dbo].[Cards]
CROSS JOIN [jewellery].[dbo].[Departments]
CROSS JOIN [jewellery].[dbo].[Operations]
WHERE [dbo].[GetCardDepartRemains] (Cards.Id, Departments.Id,Operations.[Date],NULL) = -1
But this query executes more than 2 minutes, so we need to write a new query.
My query can find all remains for each card on each department on certain date (ex. '2016-10-04')
SELECT
[Card],
Depart,
Res
FROM
(SELECT
Cards.Id as [Card],
Departments.Id as Depart,
ISNULL(SUM(CASE WHEN Operations.[Output] = 0 AND Operations.RecipientId = Departments.Id THEN 1 ELSE -1 END), 0) as Res
FROM Operations
CROSS JOIN Cards
CROSS JOIN Departments
WHERE Operations.CardId = Cards.Id
AND (Operations.[Output] = 0 AND Operations.RecipientId = Departments.Id OR Operations.Input = 0 AND Operations.SenderId = Departments.Id)
AND (Operations.[Date] <= '2016-10-04')
GROUP BY Cards.Id, Departments.Id
) as X
WHERE Res = -1
Can you help to re-write this query to find remains for all dates?
Assuming SQL Server is 2008 or above:
To find all dates, just comment out the date filter like this:
-- AND (Operations.[Date] <= '2016-10-04')
If you need to filter on a date range:
AND (Operations.[Date] between between getDate()-30 and getDate()
Changing -30 to however many days in the past. So a year ago would be -364.

Is there any way to restrict the data inserted into table if it is already present?

I have an sp which when triggered, data will be inserted into the data table. If the data being inserted is already present in the table, I don't want the data to be inserted into the table. is there anyway i could use a logic to restrict the data into table.
my query is
declare #ident int = IDENT_CURRENT( 'SADEV.RO_Transcript.ETQueueCtrl' )
insert into SADEV.RO_Transcript.ETQueueCtrl ([STU_ID],[STU_ORD_SEQ_NUM],[CreatedDate],[LastUpdatedDate],[ETQueueCtrlStatusCd],[ErrorFl])
select STU_ID
,STU_ORD_SEQ_NUM
,getdate()
,getdate()
,[ETQueueCtrlStatusCd] = 'N'
,'N'
from srdb_sr2_qa.dbo.SR0ROT rt
where STU_ORD_TYP_CD = 'A'
and ORD_DLVY_MTHD_CD = 'ET'
and STU_ORD_STAT_CD = 'C'
--and convert(varchar(1),STU_ORD_XPDT_FL) = #stu_ord_xpdt_fl
and case when #stu_ord_xpdt_fl = 'y' then GETDATE()
else case when ORD_PEND_INST_CD = '' then STU_ORD_SBM_DT+ DATEADD (mi,480,STU_ORD_SBM_TM)
else LAST_UPD_DT+ DATEADD (mi,480,LAST_UPD_TM)
end
end <= GETDATE()
select et.ETQueueCtrlID,
ro.STU_ID,
ro.STU_ORD_SEQ_NUM,
ty.CAREER_CD,
ty.CAREER_SUFX_CD
from SADEV.RO_Transcript.ETQueueCtrl et join srdb_sr2_qa.dbo.SR0ROT ro on et.STU_ID = ro.STU_ID
and et.STU_ORD_SEQ_NUM = ro.STU_ORD_SEQ_NUM
left join srdb_sr2_qa.dbo.SR0TYT ty on ro.STU_ID = ty.STU_ID
where et.ETQueueCtrlID > #ident
Could you add something like the below into the WHERE clause for the Insert?
AND
NOT EXISTS
(SELECT *
FROM sadev.ro_transcript.etqueuectrl AS trg
WHERE
rt.stu_id = trg.stu_id
AND
rt.stu_ord_seq_num = trg.stu_ord_seq_num)
You can adjust the above to filter out those data columns that shouldn't be duplicated

SQL, keep NULL instead of 0 [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
i have a sql stored procedure that for some strange reason return 0 from a user-define-function even if this return a null value.
And more strange, if i moove only this part of stored procedure to a new query, this return correctly NULL, so i cant reproduce it
incriminated column is Abbattimento and the user function is [FN_Abbattimento_Copertura_Processo], linked in this way:
OUTER APPLY dbo.FN_Abbattimento_Copertura_Processo(Kint_TP006_IdAttivita,#AnnoRiferimento, IdLiv4, SPD.Ktyi_TP001_IdSocieta, Ktyi_TP058_IdSocietaService, tyi_TP058_Copertura, 2) [acp]
instead if i add
(Select * FROM dbo.FN_Abbattimento_Copertura_Processo(...)) AS Abbattimento
i get NULL VALUE, so the problem seem the call to function with apply
this is the entire store procedure:
ALTER PROCEDURE [dbo].EXT_Pian_DettaglioProcessi
#AnnoRiferimento SMALLINT = NULL
, #IdSocieta SMALLINT = NULL
, #IDAreaIncaricata SMALLINT = NULL
, #IDAreaCoinvolta SMALLINT = NULL
, #Ufficiale BIT = 0
, #Virtuali BIT = 0
AS
BEGIN
DECLARE #VirtualiIntero AS TINYINT
SET #VirtualiIntero =
CASE #Virtuali
WHEN 0 THEN 2
ELSE 0
END
--IF #IdSocieta = 0
-- SET #IdSocieta = NULL
--print #Virtuali
SELECT
SA.nvc_TP001_Societa AS Societa
, Kint_TP006_IdAttivita AS IdAttivita
, nvc_TP006_Attivita AS Attivita
, AreaIncaricata
, CONVERT(NVARCHAR(10), DataPianificata.InizioValStatus, 103) AS DataPianificazione
, StatusAttuale.DescrizioneStatus AS StatusAttuale
, CONVERT(NVARCHAR(10), StatusAttuale.InizioValStatus, 103) AS Dal
--, IdLiv2 AS IdProcessoLivello2
, Liv2 AS ProcessoLivello2
, IdLiv4 AS IdProcessoLivello4
, Liv4 AS ProcessoLivello4
, SPD.nvc_TP001_Societa AS SocietaProcesso
, SPS.nvc_TP001_SocietaAbbreviata AS SocietaServiceProcesso
, tyi_TP058_Copertura AS Copertura
, ksin_TP058_Anno AS AnnoInizioCopertura
--, CASE Abbattimento
-- WHEN 0 THEN NULL
-- ELSE Abbattimento
-- END AS Abbattimento
, Abbattimento
, TipoCopertura
, ISNULL(CP.CoperturaOverride, 0) + ISNULL(CP.CoperturaAttConRating, 0) AS CoperturaComplessivaProcesso
FROM
-- faccio una distinct per non avere duplicati per area e perimetro
-- non lo faccio nella select iniziale perchè altrimenti dovrei selezionare anche i campi usati solo per ordinamento
(SELECT DISTINCT
Kint_TP013_IdAttivita
, Ksin_TP013_AnnoRifPian
, Ktyi_TP013_ProgressivoPian
FROM Q_TP013_Pianificazione
WHERE
(ISNULL(#IDAreaIncaricata, #IDAreaCoinvolta) IS NULL
OR
Ksin_TP013_IdArea IN (SELECT idarea FROM dbo.FN_StrutturaAree(ISNULL(#IDAreaIncaricata, #IDAreaCoinvolta)))
)) AS Pian
INNER JOIN dbo.[FN_DettaglioPianificazione](#AnnoRiferimento, #Ufficiale) AS FiltroPianificazione
ON IdAttivita = Kint_TP013_IdAttivita
AND Progressivo = Ktyi_TP013_ProgressivoPian
INNER JOIN Q_TP006_Attivita
ON Kint_TP006_IdAttivita = Kint_TP013_IdAttivita
INNER JOIN TP001_Societa AS SA
ON SA.Ktyi_TP001_IdSocieta = tyi_TP006_IdSocieta
INNER JOIN
(SELECT
nvc_TP003_Area AS AreaIncaricata
, Kint_TP024_IdAttivita
FROM
Q_TP024_LinkAttivitaArea
INNER JOIN TP003_Area
ON Ksin_TP003_IdArea = Ksin_TP024_IdArea
WHERE
tyi_TP024_IdTipoLinkAttivitaArea = 1
AND Ksin_TP024_IdArea = COALESCE(#IDAreaIncaricata, Ksin_TP024_IdArea)
) AS AI
ON Kint_TP024_IdAttivita = Kint_TP006_IdAttivita
INNER JOIN dbo.FN_CoperturaProcessiAttivita(#AnnoRiferimento,0, #VirtualiIntero,0)
ON Kint_TP058_IdAttivita = Kint_TP006_IdAttivita
LEFT OUTER JOIN dbo.[FN_StrutturaProcessi](GETDATE())
ON IdLiv4 = Ksin_TP058_IdProcesso
LEFT OUTER JOIN TP001_Societa SPD
ON SPD.Ktyi_TP001_IdSocieta = Ktyi_TP058_IdSocieta
LEFT OUTER JOIN TP001_Societa SPS
ON SPS.Ktyi_TP001_IdSocieta = Ktyi_TP058_IdSocietaService
OUTER APPLY dbo.FN_DataStatusAttivita(Kint_TP006_IdAttivita,1) AS DataPianificata
OUTER APPLY dbo.FN_Status_Attivita_Periodo(GETDATE(), Kint_TP006_IdAttivita, null, null) AS StatusAttuale
OUTER APPLY dbo.FN_Abbattimento_Copertura_Processo(Kint_TP006_IdAttivita,#AnnoRiferimento, IdLiv4, SPD.Ktyi_TP001_IdSocieta, Ktyi_TP058_IdSocietaService, tyi_TP058_Copertura, 2) [acp]
OUTER APPLY dbo.FN_CoperturaProcesso(IdLiv4, SPD.Ktyi_TP001_IdSocieta, SPS.Ktyi_TP001_IdSocieta, #AnnoRiferimento) AS CP
WHERE
Ksin_TP013_AnnoRifPian = #AnnoRiferimento
--and IdAttivita = 12331
ORDER BY
Societa
, IdAttivita
, Ord1
, Ord2
, Ord3
, Ord4
And this is user-function that calculate Abbattimento:
ALTER FUNCTION [dbo].[FN_Abbattimento_Copertura_Processo]
(
-- Add the parameters for the function here
-- Add the parameters for the function here
#idAttivita int,
#anno smallint = 0,
#idProcesso smallint = 0,
#idSocieta tinyint = 0,
#idSocietaService tinyint = 0,
#copertura tinyint = 0,
#tipoAbbattimento TINYINT = 1 --1 Dalla prima presente, 2 dalla precedente
)
RETURNS TABLE
AS
RETURN
(
SELECT
CASE
WHEN #tipoAbbattimento = 1 THEN
(SELECT TOP 1 (CAST(tyi_TP058_Copertura AS SMALLINT) - #copertura)
FROM dbo.Q_TP058_LinkAttivitaLinkProcessoSocieta
WHERE Kint_TP058_IdAttivita = #idAttivita
AND Ksin_TP058_Anno between #anno-5 and #anno
AND Ksin_TP058_IdProcesso = #idProcesso
AND Ktyi_TP058_IdSocieta = #idSocieta
AND Ktyi_TP058_IdSocietaService = #idSocietaService
ORDER BY Ksin_TP058_Anno)
WHEN #tipoAbbattimento = 2 THEN
(SELECT TOP 1 (CAST(tyi_TP058_Copertura AS SMALLINT) - #copertura)
FROM dbo.Q_TP058_LinkAttivitaLinkProcessoSocieta
WHERE Kint_TP058_IdAttivita = #idAttivita
AND Ksin_TP058_Anno between #anno-5 and #anno-1
AND Ksin_TP058_IdProcesso = #idProcesso
AND Ktyi_TP058_IdSocieta = #idSocieta
AND Ktyi_TP058_IdSocietaService = #idSocietaService
ORDER BY Ksin_TP058_Anno DESC)
END AS Abbattimento
)
as you can see in comment now i have a case to convert back 0 to NULL, but honestly i don't like much this solution.
can you help me in finding the cause?
I've not read your query, but maybe will help for you NULLIFin following:
NULLIF(col,0)
It will return NULL if your column equals to 0