Catch All Queries with a Table Valued Function - sql

I have a rather long Sql query that needs different where clauses depending on user choices.
I have done some searching, and this seems to be the most comprehensive article on the matter.
However, it doesn't mention the option of using the table valued function to achieve the same effect, and to me, this seems to be the most optimum answer.
Am I missing something?
Here is my catch all query written with the TVF:
--These paramenters will always be passed
declare #tenantId int = 7;
declare #yesterday DateTime = dateadd(day,datediff(day,1,GETUTCDATE()),0);
declare #tomorrow DateTime = dateadd(day,datediff(day,-1,GETUTCDATE()),0);
--These are optional:
declare #parentId int = 230; --In this example, #parentId is populated.
declare #ownedById int = null; --In this example, #ownedBy is not populated.
--Simple if statement:
if #parentId is not null
BEGIN
if #ownedById is not null
BEGIN
Select * from GetItemInfos(#tenantId, #yesterday, #tomorrow)
where ParentId = #parentId and OwnedById = #ownedById;
END
ELSE
Select * from GetItemInfos(#tenantId, #yesterday, #tomorrow)
where ParentId = #parentId;
END
ELSE IF #ownedById is not null
BEGIN
Select * from GetItemInfos(#tenantId, #yesterday, #tomorrow)
where OwnedById = #ownedById;
END
ELSE
Select * from GetItemInfos(#tenantId, #yesterday, #tomorrow);
And here is the TVF:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION GetItemInfos
(
#tenantId int,
#yesterday DateTime,
#tomorrow DateTime
)
RETURNS TABLE
AS
RETURN
(
Select i.Id,
i.AssignedToId,
i.ParentId,
i.OwnedById,
i.Budget,
i.CloseDate,
i.CloseStatusId,
AssignedToName = Concat(anu.FirstName, ' ', anu.LastName),
OwnedByName = Concat(anu2.FirstName, ' ', anu2.LastName),
CloseStatusName = cs.Name,
i.ItemTypeId,
ItemTypeIcon = it.Icon,
i.ImportanceTypeId,
ImportanceTypeDescription = ImportanceTypes.Description,
i.EntityStatusId,
i.DueDate,
IsOverdue =
case when i.CloseStatusId = 1 and i.DueDate <= #yesterday then Cast(1 as bit)
else Cast(0 as bit)
end,
IsDue =
case when i.CloseStatusId = 1 and i.DueDate >= #yesterday and i.DueDate < #tomorrow then cast(1 as bit)
else Cast(0 as bit)
end,
IsClosed = case when (i.CloseStatusId != 1) then cast(1 as bit) else cast(0 as bit) end,
i.Cost,
ItemTypeShowProperties = it.ShowProperties,
ItemTypeSortOrder = it.SortOrder,
PriorityTypeDescription = PriorityTypes.Description,
PriorityTypeSortOrder = PriorityTypes.SortOrder,
i.Name,
i.PriorityTypeId,
Progress = Convert(nvarchar, i.Progress) + '%',
i.SortOrder,
i.StartDate,
StatusTypeName = StatusTypes.Name,
i.TimeEstimate,
TimeScaleTypeName = TimeScaleTypes.Name
from Items i
left join AppUsers au
on i.AssignedToId = au.Id
left join AspNetUsers anu
on au.AspNetUserId = anu.id
left join AppUsers au2
on i.OwnedById = au2.Id
left join AspNetUsers anu2
on au2.AspNetUserId = anu2.id
left join CloseStatuses cs
on i.CloseStatusId = cs.id
left join ItemTypes it
on i.ItemTypeId = it.Id
left join ImportanceTypes
on i.ImportanceTypeId = ImportanceTypes.Id
left join PriorityTypes
on i.PriorityTypeId = PriorityTypes.Id
left join StatusTypes
on i.StatusTypeId = StatusTypes.Id
left join TimeScaleTypes
on i.TimeScaleTypeId = TimeScaleTypes.Id
where i.TenantId = #tenantid
)
GO
EDIT
Based on the comments, this seems to be the best way to write this:
Select * from GetItemInfos(#tenantId, #yesterday, #tomorrow)
where (#parentId is null or ParentId = #parentId) and (#ownedById is null or OwnedById = #ownedById) OPTION(RECOMPILE)

Related

Speeding up SQL query(s)

New to SQL Server so I am sorry if this is not correctly. We have a number of stored procedures. The one shown below is a good example.
The issue with the query is it works fine until there are thousands of records and it sometimes never returns. I am told this could be performance related and that queries like this could be improved by using local variables. Any insight would be appreciated...thanks
CREATE PROCEDURE [dbo].[Status_GetObjectConfigurationsPr]
#SiteID int,
#AnalogBinary bit,
#UserID int,
#ActionNumber int
AS
DECLARE #ProcName varchar(128),
#ErrorText varchar(200),
#ErrorID int,
#RoleID int
SELECT #RoleID = RoleID
FROM TESUserRole
WHERE UserID = #UserID
SELECT #ProcName = OBJECT_NAME(##PROCID)
SELECT
o.ObjectID,
o.ObjectName,
o.ObjectType,
o.ObjectURI,
o.KeyName,
c.UserDefinedUnits,
o.SiteID,
ts.SiteName,
p.Device_ID,
c.Dimension,
CASE
(SELECT COUNT(ParentObjectID) FROM TESObjectParent
WHERE ChildObjectID IN (o.ObjectID))
WHEN 2
THEN (SELECT TOP 1 b.ParentObjectID
FROM TESObject a
INNER JOIN TESObjectParent b ON a.ObjectID = b.ParentObjectID
WHERE a.ObjectID IN (SELECT ParentObjectID
FROM TESObjectParent
WHERE ChildObjectID IN (o.ObjectID))
AND ObjectType != 8
AND RelationshipType = 7)
WHEN 1
THEN (SELECT TOP 1 ParentObjectID
FROM TESObjectParent
WHERE ChildObjectID = o.ObjectID AND RelationshipType = 7)
END AS ParentObjectId,
CASE
(Select count(ParentObjectID) from TESObjectParent where ChildObjectID in (o.ObjectID) )
When 2 Then ((select top 1 ObjectName from TESObject a inner join TESObjectParent b
on a.ObjectID = b.ParentObjectID where a.ObjectID in
(Select ParentObjectID from TESObjectParent where ChildObjectID in (o.ObjectID))
and ObjectType != 8 and RelationshipType = 7))
When 1 Then PanelName
End
as PanelName
FROM
TESObject o
LEFT OUTER JOIN
TESObjectConfiguration c
ON
o.ObjectID = c.ObjectID
INNER JOIN
TESSite ts
ON
o.SiteID =ts.SiteID
INNER JOIN
TESPanel p
ON
o.Device_ID = p.Device_ID and o.SiteID = p.SiteID
INNER JOIN
TESObjectFamily f
ON
o.CustomFamilyNumber = f.FamilyNumber
INNER JOIN
TESEquipmentRole er
ON
er.FamilyID = f.FamilyID AND er.ObjectType = o.ObjectType
INNER JOIN
TESAction a
ON
er.ActionID = a.ActionID
WHERE
p.IsAppliedToLicense = 1 AND p.IsPanelEnabled = 1
AND
o.SiteID = #SiteID
AND
(c.Property_ID = 85 OR c.Property_ID is NULL)
AND(
(#AnalogBinary = 0 AND o.ObjectType IN (4,5))
OR
(#AnalogBinary = 1 AND o.ObjectType IN (1,2))
)
AND
er.RoleID = #RoleID
AND
a.ActionNumber = #ActionNumber
SET #ErrorID = ##ERROR
IF #ErrorID <> 0
BEGIN
SET #ErrorText = 'Unable to retrieve Object Configuration Information.'
GOTO ErrorHandler
END
---- Error Handling
RETURN 0
ErrorHandler:
BEGIN
RAISERROR ('PROC: %s - %s , Error: %d.', 16, 1, #ProcName, #ErrorText, #ErrorID)
END
RETURN 1

optimize complex stored procedure

I have a very complex stored procedure and i am not that strong in SQL, please any one who has a strong SQL expertise and can help me optimize or at least can give me a hint, the procedure selects the inbox messages from database for specific user and it contains many other parameters such as paging and categories and also language input and many other details:
ALTER PROCEDURE [dbo].[Inbox]
#ConfidentialityIds NVARCHAR(100) = '0,1,2,3',
#UrgencyIds NVARCHAR(100) = '0,1,2,3',
#CorrespondenceCategoryIds NVARCHAR(100) = '1,2,3,5,6,7',
#CorrespondenceExtendedCategoryIds NVARCHAR(MAX),
#IsPrivate bit = 0,
#IsSaved bit = 0,
#Importantance VARCHAR(10) = '0, 1',
#UserId uniqueidentifier,
#SelectedPage int = 1,
#PageSize int = 25,
#Now bigint,
#IsImpersonated bit,
#ActualLoggedInUserId uniqueidentifier,
#IsEnglish bit,
#OnlyArchived bit = null,
#replaceNameWithEntName bit,
#entityIds nvarchar(MAX),
#OnlyLate bit = 0,
#Statuses NVARCHAR(100) ='1,2,3,4,5',
#ApplyPageFilter bit = 1,
#IsBundled int,
#showArchivedInCCInbox bit = 0,
#appModuleId INT = 0
WITH RECOMPILE
As
BEGIN
SET transaction isolation level read uncommitted
DECLARE #lFirstRec INT, #lLastRec INT, #lTotalRows INT
SET #lFirstRec = ( #SelectedPage - 1 ) * #PageSize
SET #lLastRec = ( #SelectedPage * #PageSize + 1 )
SET #lTotalRows = #lFirstRec - #lLastRec + 1
DECLARE #isPersonalDelegationAvailable BIT = 0
IF EXISTS(
SELECT 1
FROM DelegatedToEntityUsers d
WHERE d.DelegatedToUserId = #ActualLoggedInUserId
AND d.DelegatedFromUserId = #UserId
AND
(
d.DelegatedToEntityId IS NULL OR d.DelegationType = 1
))
BEGIN
SET #isPersonalDelegationAvailable = 1
END
DECLARE #tblEntities TABLE(Value INT)
INSERT INTO #tblEntities
SELECT Value FROM SplitCommaUniqueValues(#entityIds)
Select * from (
Select (ROW_NUMBER() OVER (ORDER BY K.ActionDate DESC, K.CorrespondenceDate DESC)) AS RowIndex,
Count(*) over () AS TotalCount,*
from (
select (ROW_NUMBER() OVER (PARTITION BY CorrespondenceID Order by CorrespondenceID DESC)) AS CorrId, *
from (
SELECT Distinct * FROM
(
SELECT
CONVERT(VARCHAR(100), R.CorrespondenceActionRecipientID) Id,
A.CorrespondenceActionID ActionId,
(CASE WHEN R.RecipientType IS NULL THEN NULL ELSE CAST(RecipientType AS INT) END) RecipientType,
A.ActionTypeId,
(CASE when #IsEnglish = 1 then ATypes.FriendlyTextEN else ATypes.FriendlyTextAR end) ActionTypeName,
A.ActionCreatedByUserID SentById,
CASE
when #replaceNameWithEntName = 0 then ISNULL(ActionCreatedByUser.ShortName, ActionCreatedByUser.EmployeeName)
when #replaceNameWithEntName = 1 and SentByEntity.EntityID not in (SELECT Value FROM #tblEntities) then case when #IsEnglish = 1 then SentByEntity.EntityNameEn else SentByEntity.EntityNameAR end
when #replaceNameWithEntName = 1 and SentByEntity.EntityID in (SELECT Value FROM #tblEntities) then ISNULL(ActionCreatedByUser.ShortName, ActionCreatedByUser.EmployeeName)
END SentByFrom,
A.WithDelegateFromUserID OnBehalfOfId,
ISNULL(WithDelegateFromUser.ShortName, WithDelegateFromUser.EmployeeName) OnBehalfOfName,
R.UserId SentToId,
CASE
when #replaceNameWithEntName = 0 then ISNULL(SentToUser.ShortName, SentToUser.EmployeeName)
when #replaceNameWithEntName = 1 and SentToEntity.EntityID not in (SELECT Value FROM #tblEntities) then case when #IsEnglish = 1 then SentToEntity.EntityNameEn else SentToEntity.EntityNameAR end
when #replaceNameWithEntName = 1 and SentToEntity.EntityID in (SELECT Value FROM #tblEntities) then isnull(ISNULL(SentToUser.ShortName, SentToUser.EmployeeName), case when #IsEnglish = 1 then SentToEntity.EntityNameEn else SentToEntity.EntityNameAR end)
END SentToName,
R.EntityID SentToEntityId,
SentToEntity.EntityNameAR SentToEntityNameAR,
SentToEntity.EntityNameEN SentToEntityNameEN,
R.Seen,
(CASE WHEN MR.CorrespondenceActionRecipientID IS NOT NULL THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END) IsReadByUser,
CAST(ISNULL(FollowedByUser.IsFollowedByUser, 0) AS BIT) IsFollowedByUser,
(
CASE WHEN EXISTS(SELECT 1 FROM CorrespondenceFollowups
WHERE CorrespondenceID = C.CorrespondenceID
AND UserId = #UserId AND AssignedByUserId IS NOT NULL) THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT) END
) IsAssignedFollowToUser,
(
CASE WHEN EXISTS(SELECT 1 FROM CorrespondenceFollowups
WHERE CorrespondenceID = C.CorrespondenceID
AND AssignedByUserId = #UserId) THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT) END
) IsAssignedFollowByUser,
A.CorrespondenceID,
A.ActionDate,
A.ActionDeadlineDate,
C.CompletionDate,
C.CorrespondenceDeadlineDate CorrDeadlineDate,
C.OwnerUserID CorrOwnerId,
C.ChildNo ChildNo,
OwnerUser.EmployeeName CorrOwnerName,
C.Important,
C.UrgencyId,
C.LetterCorrespondenceId,
(CASE when #IsEnglish = 1 then U.TextEN else U.TextAR end) UrgencyText,
C.ConfidentialityId,
(CASE when #IsEnglish = 1 then Confid.TextEN else Confid.TextAR end) ConfidentialityText,
C.CorrespondenceCategoryId CategoryId,
C.CorrespondenceClassificationID CorrespondenceClassificationID,
(CASE when #IsEnglish = 1 then CCat.TextEN else CCat.TextAR end) CategoryName,
CCat.ColorClass ColorClass,
C.Subject,
c.CorrespondenceFormula,
C.InternalSenderEntityId,
C.InternalRecipientEntityId,
C.[Sequence] [Sequence],
C.Year,
C.CompletionStatus Status,
Null Number,
(CASE WHEN (
(
(A.ActionDeadlineDate IS NOT NULL AND A.ActionDeadlineDate < #Now)
OR
(C.CorrespondenceDeadlineDate IS NOT NULL AND C.CorrespondenceDeadlineDate < #Now)
)
AND
C.[Closed-Archived] = 0) THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END) IsLate,
CAST(0 AS BIT) HasAnyEvents,
C.CreatedByUserId,
CreatedByUser.EmployeeName CreatedByUserName,
CAST(C.CorrespondenceDate AS VARCHAR(50)) CorrDate,
C.CorrespondenceDate,
C.[Closed-Archived] ClosedArchived,
C.IsSaved SavedActionTaken,
((CASE WHEN C.Important = 1 THEN CASE WHEN #IsEnglish = 1 THEN N'Important' ELSE N'هامة' END ELSE '' END) + (CASE WHEN C.Important = 1 AND C.UrgencyID <> 0 THEN CASE WHEN #IsEnglish = 1 THEN N' and ' ELSE N' و ' END ELSE '' END) + (CASE WHEN C.UrgencyID <> 0 THEN (CASE when #IsEnglish = 1 then U.TextEN else U.TextAR end) ELSE '' END)) ImportantUrgencyText,
CAST(C.IsAutoSaved AS BIT) IsAutoSaved,
-- *******************************************************************
rem.ReminderDate as CorrespondenceReminderDateTime,
remAction.ReminderDate as ActionReminderDateTime
FROM (
SELECT * FROM Correspondences CC
WHERE CC.IsDeleted = 0
AND CC.LetterCorrespondenceId IS NULL
AND (CC.ConfidentialityId IN (SELECT [Value] FROM SplitCommaUniqueValues(#ConfidentialityIds)))
AND
( #IsPrivate = 0 OR
(
#IsPrivate = 1 AND CC.IsForPresident = 1
)
)
AND
(
(CC.IsSaved = case when #IsSaved =1 then 1 else CC.IsSaved end)
)
AND (#appModuleId = 0 OR CC.AppModuleId = #appModuleId)
AND (CC.UrgencyID IN (SELECT value FROM SplitCommaUniqueValues(#UrgencyIds)))
AND (CC.Important IN (SELECT value FROM SplitCommaUniqueValues(#Importantance)))
AND CC.CompletionStatus IN(SELECT value FROM SplitComma(#Statuses))
) C
LEFT JOIN CorrespondenceExtendedDetails CorrExt
ON CorrExt.CorrespondenceID = C.CorrespondenceID
LEFT JOIN CorrespondenceActions A
ON C.CorrespondenceID = A.CorrespondenceID
AND A.IsDeleted = 0
AND A.ActionTypeID != 7 -- إنهاء التذكير
LEFT JOIN CorrespondenceActionRecipients R
ON A.CorrespondenceActionID = R.CorrespondenceActionID
AND (
R.AsCopy = 1
)
JOIN Urgencies U
ON C.UrgencyID = U.ID
JOIN ActionTypes ATypes
ON A.ActionTypeID = ATypes.ID
JOIN CorrespondenceCategories CCat
ON C.CorrespondenceCategoryId = CCat.ID
JOIN Confidentialities Confid
ON C.ConfidentialityID = Confid.ID
LEFT JOIN Users ActionCreatedByUser
ON A.ActionCreatedByUserID = ActionCreatedByUser.UserId
LEFT JOIN Users WithDelegateFromUser
ON A.WithDelegateFromUserID = WithDelegateFromUser.UserID
LEFT JOIN Entities SentByEntity
ON A.ActionCreatedByUserEntityId = SentByEntity.EntityID
LEFT JOIN Users SentToUser
ON R.UserId = SentToUser.UserId
LEFT JOIN Entities SentToEntity
ON R.EntityID = SentToEntity.EntityID
LEFT JOIN Users OwnerUser
ON C.OwnerUserID = OwnerUser.UserId
LEFT JOIN Users CreatedByUser
ON C.CreatedByUserID = CreatedByUser.UserId
LEFT JOIN MarkAsReads MR
ON R.CorrespondenceActionRecipientID = MR.CorrespondenceActionRecipientID
AND MR.UserId = #UserId
OUTER APPLY
(
SELECT TOP 1 1 IsFollowedByUser
FROM CorrespondenceFollowups CF
WHERE CF.CorrespondenceId = C.CorrespondenceID
AND CF.UserId = #UserId
AND CF.AssignedByUserId IS NULL
) FollowedByUser
-- *******************************************************************
LEFT JOIN LinkedCorrespondenceSchedules CS on CS.CorrespondenceID = C.CorrespondenceID
LEFT JOIN Reminder rem on rem.ReferenceId=C.CorrespondenceID AND rem.ReferenceType = 1 AND rem.CreatedByUserId=#UserId AND (rem.[Status] = 1 OR rem.[Status] = 2)
Left JOIN Reminder remAction on remAction.ReferenceId = A.CorrespondenceActionID AND remAction.ReferenceType = 2 AND remAction.CreatedByUserId=#UserId AND (remAction.[Status] = 1 OR remAction.[Status] = 2)
-- *******************************************************************
WHERE (
(C.CorrespondenceCategoryId IN (SELECT Value FROM SplitComma(#CorrespondenceCategoryIds)) AND CorrExt.CorrespondenceExtendedCategoryId IS NULL)
OR (CorrExt.CorrespondenceExtendedCategoryId IN (SELECT Value FROM SplitComma(#CorrespondenceExtendedCategoryIds)))
)
AND
(
-- Personal
(
(
(#IsImpersonated = 0 AND R.UserId = #UserId)
OR
(#IsImpersonated = 1 AND R.UserId = #UserId AND #isPersonalDelegationAvailable = 1)
)
AND R.RecipientType = 1 AND R.UserId Is Not null
)
OR
-- Me as Manager (Impersonation mode handled from code by sending the proper Entity Ids.
(
(R.EntityID IN (SELECT Value FROM #tblEntities) AND R.EntityID Is Not null AND R.RecipientType != 1)
)
)
AND C.[Closed-Archived] = Case When #showArchivedInCCInbox = 1 Then 0 Else C.[Closed-Archived] End
AND R.UserTokeAction = 0
AND NOT EXISTS (
SELECT 1 FROM Correspondences CC
INNER JOIN CorrespondenceLinks CL
ON CC.CorrespondenceID = CL.LinkedCorrespondenceID AND CC.CorrespondenceID = C.CorrespondenceID AND CL.LinkTypeID = #IsBundled
)
) T
WHERE T.LetterCorrespondenceId is null
) as ttt
) K where CorrId = 1
)N where (#ApplyPageFilter = 0 OR ( RowIndex > #lFirstRec AND RowIndex < #lLastRec))
Order by
ActionDate DESC, CorrespondenceDate
option(recompile)
END

Stored Procedure slowness after upgrade to SQL Server 2014

We have done a SQL Server upgrade from 2005 to 2014. Post upgrade one of the stored procedures is running very slow. It used to take about 10 mins which has now increased to 23 mins.
On further investigating, the execution time after fresh upgrade was perfectly fine and only after 3-4 executions it gets increased. I tried restoring the fresh database again and can confirm the above behaviour. Can someone help me out, since I have no clue what's happening!
I am a core DBA and not an application DBA so I don't have much knowledge about how stored procedures behave. Any help would be appreciated.
I am running using parameters :
exec [usp_RecalculateMV] '10', 8, 2015
Stored procedure code:
CREATE PROCEDURE [dbo].[usp_RecalculateMV]
(#MarketID nvarchar(100),
#FromMonth int,
#FromYear int)
AS
BEGIN
--variable to hold any errors generated by the procedure
DECLARE #ErrorCode INT
DECLARE #MarketIDs INT
DECLARE #Failed nvarchar(100)
DECLARE #SplitBy nvarchar(10)
DECLARE #StartDate nvarchar(11)
--
-- Changes done by Rupan
-- Start (SER000008289)
DECLARE #cQtytoSplit FLOAT
DECLARE #cOtherQty FLOAT
DECLARE #cSplitThreshold INT
DECLARE #cWeeklySplit NVARCHAR(35)
DECLARE #cWeeklyBufferSplit NVARCHAR(35)
DECLARE #SplitType VARCHAR(15)
DECLARE #cSplitValue FLOAT
DECLARE #jSplit INT
SET #jSplit = 1
DECLARE #iSplit INT
SET #iSplit = 1
DECLARE #cPackCode NVARCHAR(50)
DECLARE #cCustCode NVARCHAR(50)
DECLARE #Week1Cursor INT
DECLARE #Week2Cursor INT
DECLARE #Week3Cursor INT
DECLARE #Week4Cursor INT
DECLARE #QtytoSplitCursor FLOAT
DECLARE #OtherQtyCursor FLOAT
DECLARE #itemp INT
SET #itemp = 1
DECLARE #tempCount INT
DECLARE #tempPackCode NVARCHAR(50)
DECLARE #tempCustomerCode NVARCHAR(50)
DECLARE #tempWeeklyMV VARCHAR(85)
DECLARE #tempWeeklBuffer VARCHAR(85)
DECLARE #tempMVQTY FLOAT
DECLARE #tempBufferQTY FLOAT
CREATE TABLE #tmp_IntialLoad ( ID INT IDENTITY(1,1),
MVQty FLOAT,
BufferQty FLOAT,
SplitThreshold INT,
WeeklyMVQty NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS,
WeeklyBufferQty NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS,
PackCode NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS,
CustomerCode NVARCHAR(85) COLLATE SQL_Latin1_General_CP1_CI_AS
);
CREATE TABLE #tmp_SplitQTY ( ID INT IDENTITY(1,1),
SplitType VARCHAR(15) COLLATE SQL_Latin1_General_CP1_CI_AS,
QtytoSplit FLOAT,
OtherQty FLOAT,
MarketID NVARCHAR(85) COLLATE SQL_Latin1_General_CP1_CI_AS,
Code NVARCHAR(85) COLLATE SQL_Latin1_General_CP1_CI_AS,
CustomerCode NVARCHAR(85) COLLATE SQL_Latin1_General_CP1_CI_AS,
Week1 INT,
Week2 INT,
Week3 INT,
Week4 INT,
Week1Buffer INT,
Week2Buffer INT,
Week3Buffer INT,
Week4Buffer INT
);
CREATE TABLE #tmp_SplitBufferQTY ( ID INT IDENTITY(1,1),
SplitType VARCHAR(15) COLLATE SQL_Latin1_General_CP1_CI_AS,
QtytoSplit FLOAT,
OtherQty FLOAT,
MarketID NVARCHAR(85) COLLATE SQL_Latin1_General_CP1_CI_AS,
Code NVARCHAR(85) COLLATE SQL_Latin1_General_CP1_CI_AS,
CustomerCode NVARCHAR(85) COLLATE SQL_Latin1_General_CP1_CI_AS,
Week1 INT,
Week2 INT,
Week3 INT,
Week4 INT
);
CREATE TABLE #tmp_FinalSplitQTY ( ID INT IDENTITY(1,1),
MarketID NVARCHAR(85) COLLATE SQL_Latin1_General_CP1_CI_AS,
Code NVARCHAR(85) COLLATE SQL_Latin1_General_CP1_CI_AS,
CustomerCode NVARCHAR(85) COLLATE SQL_Latin1_General_CP1_CI_AS,
Week1 INT,
Week2 INT,
Week3 INT,
Week4 INT,
Week1Buffer INT,
Week2Buffer INT,
Week3Buffer INT,
Week4Buffer INT,
QtytoSplit FLOAT,
OtherQty FLOAT
);
-- END
--table struc to hold the split string passed in above
DECLARE #T_TBL_Market TABLE
(
ID INT IDENTITY(1,1),
MarketID int --nvarchar(100)
)
--populate the temporary table with the split market id's
INSERT INTO #T_TBL_Market
SELECT * FROM dbo.Split(#MarketID, ',')
SET #StartDate = dbo.GetSafeDateFormat(1, #FromMonth, #FromYear)
--create a cursor to loop through the market id's
/* Start - Rupan
DECLARE MarketCursor CURSOR FOR
SELECT MarketID FROM #T_TBL_Market
--Open
OPEN MarketCursor
--loop through the markets
FETCH NEXT FROM MarketCursor
INTO #MarketIDs
******* End */
DECLARE #iMarketID INT
SET #iMarketID = 1
DECLARE #iCount INT
SELECT #iCount = COUNT(*) FROM #T_TBL_Market
/* Start - Rupan
WHILE ##FETCH_STATUS = 0
End */
WHILE( #iMarketID <= #iCount )
BEGIN
SELECT #MarketIDs = MarketID FROM #T_TBL_Market WHERE ID = #iMarketID
Print 'Inside While'
--Changes done by Parag on 08-04-2010, inserting values for customer detail
--Deleting old values
DELETE from TBL_CUSTOMER_CODE
INSERT INTO TBL_CUSTOMER_CODE(CustomerSplitID,CustomerID, Week1Split, Week2Split, Week3Split, Week4Split, SplitThreshold, CustomerCode)
SELECT dbo.TBL_CUSTOMER_SPLIT.CustomerSplitID, dbo.TBL_CUSTOMER.CustomerID, ISNULL(dbo.TBL_CUSTOMER_SPLIT.Week1Split, 25) AS Week1Split,
ISNULL(dbo.TBL_CUSTOMER_SPLIT.Week2Split, 25) AS Week2Split, ISNULL(dbo.TBL_CUSTOMER_SPLIT.Week3Split, 25) AS Week3Split,
ISNULL(dbo.TBL_CUSTOMER_SPLIT.Week4Split, 25) AS Week4Split, dbo.TBL_CUSTOMER_SPLIT.SplitThreshold,
ISNULL(dbo.TBL_CUSTOMER.CustomerCdSoldTo, '') + ISNULL(dbo.TBL_CUSTOMER.CustomerCdShipTo, '') AS CustomerCode
FROM dbo.TBL_CUSTOMER LEFT OUTER JOIN
dbo.TBL_CUSTOMER_SPLIT ON dbo.TBL_CUSTOMER.CustomerID = dbo.TBL_CUSTOMER_SPLIT.CustomerID
WHERE TBL_CUSTOMER.marketid =#MarketIDs
--Changes end
--start a transaction to roll back if things go awry
BEGIN TRAN
--delete the data for this market including and after the startdate
Print'Before Delete'
DELETE FROM TBL_CALCULATED_MV
WHERE MarketID = #MarketIDs
AND [Month] >= #StartDate
Print'After Delete'
--check for errors
SELECT #ErrorCode = ##Error
--if no errors continue
IF #ErrorCode = 0
BEGIN
Print'Inserting into CalculatedMV table'
--do the basic recalculation of the MV and Buffer
INSERT INTO TBL_CALCULATED_MV(
MarketName, GroupDescription, MCCode,
ChannelDesc, PackCode, PackDesc, [Month],
MVQty,BufferQty,BufferPercentage,
LocalCustomerCode,LocalCustomerName,
CustomerCdSoldTo, CustomerCdShipTo,
BrandName, BrandCode,
MinMV, MarketID,
IntlCode, EPVOrgCode, AVOrgCode, LDDQty
)
SELECT DISTINCT TBL_MARKET_COMPANY.MarketName, TBL_GROUP.GroupDescription, TBL_MARKET_COMPANY.MCCode,
TBL_CHANNEL.ChannelDesc, VW_BASE_MV.PackCode, TBL_MARKET_PACK.PackDesc, VW_BASE_MV.[Month],
VW_BASE_MV.RoundedBaseMV AS MVQty,
dbo.CalculateBuffer(VW_BASE_MV.RoundedBaseMV, VW_LATEST_BUFFER.MonthValue, VW_LATEST_MINMV.MonthValue) AS BufferQty,
VW_LATEST_BUFFER.MonthValue AS BufferPercentage,
CASE WHEN TBL_CUSTOMER.CustomerCdShipTo IS NULL THEN
TBL_CUSTOMER.CustomerCdSoldTo
ELSE
TBL_CUSTOMER.CustomerCdShipTo
END AS LocalCustomerCode,
TBL_CUSTOMER.CustDescription, TBL_CUSTOMER.CustomerCdSoldTo, TBL_CUSTOMER.CustomerCdShipTo,
TBL_BRAND.BrandName, TBL_BRAND.BrandCode,
VW_LATEST_MINMV.MonthValue, VW_BASE_MV.MarketID,
TBL_MARKET_PACK.IntlCode, TBL_MARKET_COMPANY.EPVOrgCode, TBL_MARKET_COMPANY.AVOrgCode,
VW_BASE_MV.LDD
FROM TBL_CHANNEL
INNER JOIN VW_BASE_MV
ON TBL_CHANNEL.ChannelID = VW_BASE_MV.ChannelID
INNER JOIN TBL_MARKET_COMPANY
ON TBL_MARKET_COMPANY.MarketID = VW_BASE_MV.MarketID
INNER JOIN TBL_GROUP
ON TBL_GROUP.GroupID = TBL_MARKET_COMPANY.GroupID
INNER JOIN TBL_MARKET_PACK
ON VW_BASE_MV.MarketID = TBL_MARKET_PACK.MarketID
AND VW_BASE_MV.PackCode = TBL_MARKET_PACK.PackCode
INNER JOIN TBL_BRAND
ON TBL_BRAND.BrandID = TBL_MARKET_PACK.BrandID
LEFT OUTER JOIN TBL_CUSTOMER
ON VW_BASE_MV.CustomerID = TBL_CUSTOMER.CustomerID
LEFT OUTER JOIN VW_LATEST_BUFFER
ON VW_BASE_MV.MarketID = VW_LATEST_BUFFER.MarketID
AND VW_BASE_MV.PackCode = VW_LATEST_BUFFER.PackCode
AND VW_BASE_MV.ChannelID = VW_LATEST_BUFFER.ChannelID
AND VW_BASE_MV.[Month] = VW_LATEST_BUFFER.[Month]
LEFT OUTER JOIN VW_LATEST_MINMV
ON VW_BASE_MV.MarketID = VW_LATEST_MINMV.MarketID
AND VW_BASE_MV.PackCode = VW_LATEST_MINMV.PackCode
AND VW_BASE_MV.ChannelID = VW_LATEST_MINMV.ChannelID
AND VW_BASE_MV.[Month] = VW_LATEST_MINMV.[Month]
WHERE VW_BASE_MV.[Month] >= #StartDate
AND VW_BASE_MV.MarketID = #MarketIDs
AND VW_BASE_MV.RoundedBaseMV > 0
AND CASE WHEN TBL_CUSTOMER.CustomerCdShipTo IS NULL THEN
TBL_CUSTOMER.CustomerCdSoldTo
ELSE
TBL_CUSTOMER.CustomerCdShipTo
END IS NOT NULL --prevents customer still in the market share table
--but not in the customer table from being passed through
--to the calculated mv table
--check for errors
SELECT #ErrorCode = ##Error
Print 'After Inserting into CalculatedMV table'
END
IF #ErrorCode = 0 -- Start End of Errorcode 1
BEGIN
--find out if this market splits by Pack or by customer
SELECT #SplitBy = ISNULL(SplitBy, 'Unassigned')
FROM TBL_MARKET_COMPANY
WHERE MarketID = #MarketIDs
--calculate the split MV and default the SumWeeklyMV and SumWeeklyBuffer
--fields to the MV and Buffer quantities
IF ISNULL(#SplitBy, 'Unassigned') = 'Unassigned'
BEGIN
UPDATE TBL_CALCULATED_MV
SET
Week1MV = 0,
Week2MV = 0,
Week3MV = 0,
Week4MV = 0,
Week1Buffer = 0,
Week2Buffer = 0,
Week3Buffer = 0,
Week4Buffer = 0,
SumWeeklyMV = MVQty,
SumWeeklyBuffer = BufferQty,
Split = 0
WHERE
TBL_CALCULATED_MV.MarketID = #MarketIDs
AND
TBL_CALCULATED_MV.[Month] >= #StartDate
END
IF #SplitBy = 'Pack' -- Start of Pack
BEGIN
Print 'Entering Pack sum update'
UPDATE TBL_CALCULATED_MV
SET
SumWeeklyMV = MVQty,
SumWeeklyBuffer = BufferQty,
Split = CASE WHEN MP.SplitThreshold IS NULL THEN
0
WHEN MVQty + BufferQty < MP.SplitThreshold THEN
0
ELSE
1
END
FROM TBL_CALCULATED_MV
LEFT OUTER JOIN
VW_PACK_SPLIT
ON
TBL_CALCULATED_MV.PackCode = VW_PACK_SPLIT.PackCode
AND
TBL_CALCULATED_MV.MarketID = VW_PACK_SPLIT.MarketID
INNER JOIN
TBL_MARKET_PACK MP
ON
TBL_CALCULATED_MV.MarketID = MP.MarketID
AND
TBL_CALCULATED_MV.PackCode = MP.PackCode
WHERE
TBL_CALCULATED_MV.MarketID = #MarketIDs
AND
TBL_CALCULATED_MV.[Month] >= #StartDate
Print 'After sum update'
Print'Before inserting into Initialload table'
/* Changes Done By Rupan (SER00008289)*/
INSERT INTO #tmp_IntialLoad
SELECT DISTINCT
MVQty,
BufferQty,
MP.SplitThreshold,
CONVERT(VARCHAR,Week1Split)+','+CONVERT(VARCHAR,Week2Split)+','+CONVERT(VARCHAR,Week3Split)+','+CONVERT(VARCHAR,Week4Split),
CONVERT(VARCHAR,Week1Split)+','+CONVERT(VARCHAR,Week2Split)+','+CONVERT(VARCHAR,Week3Split)+','+CONVERT(VARCHAR,Week4Split),
MP.PackCode,
TBL_CALCULATED_MV.LocalCustomerCode
FROM
TBL_CALCULATED_MV
LEFT OUTER JOIN VW_PACK_SPLIT
ON TBL_CALCULATED_MV.PackCode = VW_PACK_SPLIT.PackCode
AND TBL_CALCULATED_MV.MarketID = VW_PACK_SPLIT.MarketID
INNER JOIN TBL_MARKET_PACK MP
ON TBL_CALCULATED_MV.MarketID = MP.MarketID
AND TBL_CALCULATED_MV.PackCode = MP.PackCode
WHERE TBL_CALCULATED_MV.MarketID = #MarketIDs
AND TBL_CALCULATED_MV.[Month] >= #StartDate
AND TBL_CALCULATED_MV.Split=1
SET #jSplit = 1
Print 'After Initial load and before looping Initial Load'
WHILE(#jSplit <= (SELECT Count(*) FROM #tmp_IntialLoad ))
BEGIN
SELECT #cQtytoSplit = MVQty,
#cOtherQty = BufferQty,
#cSplitThreshold = SplitThreshold,
#cWeeklySplit = WeeklyMVQty,
#cWeeklyBufferSplit = WeeklyBufferQty,
#cPackCode = PackCode,
#cCustCode = CustomerCode
FROM
#tmp_IntialLoad
WHERE
ID = #jSplit
INSERT INTO #tmp_SplitQTY(SplitType,QtytoSplit,OtherQty,MarketID,Code,CustomerCode,Week1,Week2,Week3,Week4)
EXEC CalculateSplitMV_working_SER8289 #cQtytoSplit,#cOtherQty,#cSplitThreshold,#cWeeklySplit,'MV',#MarketIDs,#cPackCode,NULL
INSERT INTO #tmp_SplitBufferQTY(SplitType,QtytoSplit,OtherQty,MarketID,Code,CustomerCode,Week1,Week2,Week3,Week4)
EXEC CalculateSplitMV_working_SER8289 #cOtherQty,#cQtytoSplit,#cSplitThreshold,#cWeeklyBufferSplit,'BUFFER',#MarketIDs,#cPackCode,NULL
SET #jSplit = #jSplit + 1
END
Print 'After looping Initial Load and before updating #tmp_SplitQTY'
UPDATE ts
SET
ts.Week1Buffer = tsb.Week1,
ts.Week2Buffer = tsb.Week2,
ts.Week3Buffer = tsb.Week3,
ts.Week4Buffer = tsb.Week4
FROM
#tmp_SplitQTY ts,#tmp_SplitBufferQTY tsb
WHERE
ts.ID = tsb.ID
AND
ts.MarketID = tsb.MarketID
AND
ts.Code = tsb.Code
SELECT #tempCount = COUNT(*) FROM #tmp_SplitQTY
Print 'After updating #tmp_SplitQTY and before calling usp_Forecast_Calc_BoxSize sp '
WHILE(#itemp <= #tempCount)
BEGIN
SELECT #tempPackCode = Code,
#tempCustomerCode = CustomerCode,
#tempWeeklyMV = CONVERT(VARCHAR,Week1)+','+CONVERT(VARCHAR,Week2)+','+CONVERT(VARCHAR,Week3)+','+CONVERT(VARCHAR,Week4),
#tempWeeklBuffer = CONVERT(VARCHAR,Week1Buffer)+','+CONVERT(VARCHAR,Week2Buffer)+','+CONVERT(VARCHAR,Week3Buffer)+','+CONVERT(VARCHAR,Week4Buffer),
#tempMVQTY = QtytoSplit,
#tempBufferQTY = OtherQty
FROM
#tmp_SplitQTY
WHERE
ID = #itemp
INSERT INTO #tmp_FinalSplitQTY(MarketID,Code,CustomerCode,Week1,Week2,Week3,Week4,Week1Buffer,Week2Buffer,Week3Buffer,Week4Buffer,QtytoSplit,OtherQty)
EXEC usp_Forecast_Calc_BoxSize #tempWeeklyMV,#tempWeeklBuffer,#MarketIDs,#tempPackCode,NULL,#tempMVQTY,#tempBufferQTY
-- EXEC usp_Forecast_Calc_BoxSize '1,0,0,0','1,1,1,0',5,1120200,NULL,1,3
SET #itemp = #itemp + 1
END
PRINT 'after usp_Forecast_Calc_BoxSize and before Entering MV/Buffer Update'
/* Updating MV Quantity Weekly Split value */
UPDATE tc
SET
tc.Week1MV = tfs.Week1,
tc.Week2MV = tfs.Week2,
tc.Week3MV = tfs.Week3,
tc.Week4MV = tfs.Week4,
tc.Week1Buffer = tfs.Week1Buffer,
tc.Week2Buffer = tfs.Week2Buffer,
tc.Week3Buffer = tfs.Week3Buffer,
tc.Week4Buffer = tfs.Week4Buffer
FROM
TBL_CALCULATED_MV tc,#tmp_FinalSplitQTY tfs
WHERE
tc.PackCode = tfs.code
AND
tc.MarketID = tfs.MarketID
AND
tc.MarketID = #MarketIDs
AND
tc.MVQty = tfs.QtytoSplit
AND
tc.BufferQty = tfs.OtherQty
AND
tc.[Month]>= #StartDate
AND
tc.Split=1
PRINT 'after MV/Buffer Update'
END -- End of Pack Condition
IF #SplitBy = 'Customer' -- Start of Customer condition
BEGIN
Print 'Entering Customer Sum update'
UPDATE TBL_CALCULATED_MV
SET
SumWeeklyMV = MVQty,
SumWeeklyBuffer = BufferQty,
Split = CASE WHEN MP.SplitThreshold IS NULL THEN
0
WHEN MVQty + BufferQty < MP.SplitThreshold THEN
0
ELSE
1
END
FROM TBL_CALCULATED_MV
--LEFT OUTER JOIN VW_CUSTOMER_SPLIT
LEFT OUTER JOIN TBL_CUSTOMER_CODE
ON TBL_CALCULATED_MV.LocalCustomerCode = TBL_CUSTOMER_CODE.CustomerCode
--ON TBL_CALCULATED_MV.LocalCustomerCode = VW_CUSTOMER_SPLIT.CustomerCode
INNER JOIN TBL_MARKET_PACK MP
ON TBL_CALCULATED_MV.MarketID = MP.MarketID
AND TBL_CALCULATED_MV.PackCode = MP.PackCode
WHERE TBL_CALCULATED_MV.MarketID = #MarketIDs
AND TBL_CALCULATED_MV.[Month] >= #StartDate
--* Updating MV Quantity Weekly Split value */
/* Updating MV Quantity Weekly Split value */
Print 'After Customer Sum update'
Print'Before inserting into Initialload table'
INSERT INTO #tmp_IntialLoad
SELECT DISTINCT
MVQty,
BufferQty,
MP.SplitThreshold,
CONVERT(VARCHAR,Week1Split)+','+CONVERT(VARCHAR,Week2Split)+','+CONVERT(VARCHAR,Week3Split)+','+CONVERT(VARCHAR,Week4Split),
CONVERT(VARCHAR,Week1Split)+','+CONVERT(VARCHAR,Week2Split)+','+CONVERT(VARCHAR,Week3Split)+','+CONVERT(VARCHAR,Week4Split),
TBL_CALCULATED_MV.PackCode,
TBL_CALCULATED_MV.LocalCustomerCode
FROM
TBL_CALCULATED_MV
--LEFT OUTER JOIN VW_CUSTOMER_SPLIT
LEFT OUTER JOIN TBL_CUSTOMER_CODE
ON TBL_CALCULATED_MV.LocalCustomerCode = TBL_CUSTOMER_CODE.CustomerCode
--ON TBL_CALCULATED_MV.LocalCustomerCode = VW_CUSTOMER_SPLIT.CustomerCode
INNER JOIN TBL_MARKET_PACK MP
ON TBL_CALCULATED_MV.MarketID = MP.MarketID
AND TBL_CALCULATED_MV.PackCode = MP.PackCode
WHERE TBL_CALCULATED_MV.MarketID = #MarketIDs
AND TBL_CALCULATED_MV.[Month] >= #StartDate
AND TBL_CALCULATED_MV.Split=1
SET #jSplit = 1
Print 'After Initial load and before looping Initial Load'
WHILE(#jSplit <= (SELECT Count(*) FROM #tmp_IntialLoad ))
BEGIN
SELECT #cQtytoSplit = MVQty,
#cOtherQty = BufferQty,
#cSplitThreshold = SplitThreshold,
#cWeeklySplit = WeeklyMVQty,
#cWeeklyBufferSplit = WeeklyBufferQty,
#cPackCode = PackCode,
#cCustCode = CustomerCode
FROM
#tmp_IntialLoad
WHERE
ID = #jSplit
INSERT INTO #tmp_SplitQTY(SplitType,QtytoSplit,OtherQty,MarketID,Code,CustomerCode,Week1,Week2,Week3,Week4)
EXEC CalculateSplitMV_working_SER8289 #cQtytoSplit,#cOtherQty,#cSplitThreshold,#cWeeklySplit,'MV',#MarketIDs,#cPackCode,#cCustCode
INSERT INTO #tmp_SplitBufferQTY(SplitType,QtytoSplit,OtherQty,MarketID,Code,CustomerCode,Week1,Week2,Week3,Week4)
EXEC CalculateSplitMV_working_SER8289 #cOtherQty,#cQtytoSplit,#cSplitThreshold,#cWeeklyBufferSplit,'BUFFER',#MarketIDs,#cPackCode,#cCustCode
SET #jSplit = #jSplit + 1
END
Print 'After looping Initial Load and before updating #tmp_SplitQTY'
UPDATE ts
SET
ts.Week1Buffer = tsb.Week1,
ts.Week2Buffer = tsb.Week2,
ts.Week3Buffer = tsb.Week3,
ts.Week4Buffer = tsb.Week4
FROM
#tmp_SplitQTY ts,#tmp_SplitBufferQTY tsb
WHERE
ts.ID = tsb.ID
AND
ts.MarketID = tsb.MarketID
AND
ts.Code = tsb.Code
AND
ts.CustomerCode = tsb.CustomerCode
SELECT #tempCount = COUNT(*) FROM #tmp_SplitQTY
Print 'After updating #tmp_SplitQTY and before calling usp_Forecast_Calc_BoxSize sp '
WHILE(#itemp <= #tempCount)
BEGIN
SELECT #tempPackCode = Code,
#tempCustomerCode = CustomerCode,
#tempWeeklyMV = CONVERT(VARCHAR,Week1)+','+CONVERT(VARCHAR,Week2)+','+CONVERT(VARCHAR,Week3)+','+CONVERT(VARCHAR,Week4),
#tempWeeklBuffer = CONVERT(VARCHAR,Week1Buffer)+','+CONVERT(VARCHAR,Week2Buffer)+','+CONVERT(VARCHAR,Week3Buffer)+','+CONVERT(VARCHAR,Week4Buffer),
#tempMVQTY = QtytoSplit,
#tempBufferQTY = OtherQty
FROM
#tmp_SplitQTY
WHERE
ID = #itemp
INSERT INTO #tmp_FinalSplitQTY(MarketID,Code,CustomerCode,Week1,Week2,Week3,Week4,Week1Buffer,Week2Buffer,Week3Buffer,Week4Buffer,QtytoSplit,OtherQty)
EXEC usp_Forecast_Calc_BoxSize #tempWeeklyMV,#tempWeeklBuffer,#MarketIDs,#tempPackCode,#tempCustomerCode,#tempMVQTY,#tempBufferQTY
SET #itemp = #itemp + 1
END
PRINT 'after usp_Forecast_Calc_BoxSize and before Entering MV/Buffer Update'
/* Updating MV Quantity Weekly Split value */
UPDATE tc
SET
tc.Week1MV = tfs.Week1,
tc.Week2MV = tfs.Week2,
tc.Week3MV = tfs.Week3,
tc.Week4MV = tfs.Week4,
tc.Week1Buffer = tfs.Week1Buffer,
tc.Week2Buffer = tfs.Week2Buffer,
tc.Week3Buffer = tfs.Week3Buffer,
tc.Week4Buffer = tfs.Week4Buffer
FROM
TBL_CALCULATED_MV tc,#tmp_FinalSplitQTY tfs
WHERE
tc.PackCode = tfs.code
AND
tc.MarketID = tfs.MarketID
AND
tc.LocalCustomerCode = tfs.CustomerCode
AND
tc.MarketID = #MarketIDs
AND
tc.MVQty = tfs.QtytoSplit
AND
tc.BufferQty = tfs.OtherQty
AND
tc.[Month]>= #StartDate
AND
tc.Split=1
/* End */
PRINT 'after MV/Buffer Update'
--check for errors
SELECT #ErrorCode = ##Error
END -- End of Customer condition
END -- End of Errorcode 1
IF #ErrorCode = 0
BEGIN
Print 'Inside sumweekly update'
--Update the SumWeeklyMV and SumWeeklyBuffer fields to be the sum of the
--splits for the rows that are to be split
UPDATE TBL_CALCULATED_MV
SET
TBL_CALCULATED_MV.SumWeeklyMV = ISNULL(Week1MV,0) + ISNULL(Week2MV,0) + ISNULL(Week3MV,0) + ISNULL(Week4MV,0),
TBL_CALCULATED_MV.SumWeeklyBuffer = ISNULL(Week1Buffer,0) + ISNULL(Week2Buffer,0) + ISNULL(Week3Buffer,0) + ISNULL(Week4Buffer,0)
WHERE TBL_CALCULATED_MV.Split=1
and TBL_CALCULATED_MV.MarketID = #MarketIDs
AND TBL_CALCULATED_MV.[Month] >= #StartDate
--check for errors
select #ErrorCode = ##Error
END
IF #ErrorCode = 0
COMMIT TRAN
ELSE
BEGIN
ROLLBACK TRAN
set #Failed = #Failed + ',' + #MarketIDs
END
SET #ErrorCode = 0
/* Start - Rupan
FETCH NEXT FROM MarketCursor
INTO #MarketIDs
End */
DELETE FROM #tmp_IntialLoad
DELETE FROM #tmp_SplitQTY
DELETE FROM #tmp_FinalSplitQTY
SET #iMarketID = #iMarketID + 1
END
/*CLOSE MarketCursor
DEALLOCATE MarketCursor
*/
DROP TABLE #tmp_IntialLoad
DROP TABLE #tmp_SplitQTY
DROP TABLE #tmp_FinalSplitQTY
--IF #Failed is null
--SELECT #SuccessFail = 'All markets were successfully re-calculated'
--ELSE
-- SELECT #SuccessFail=#Failed
END -- END of Procedure Begin
GO
If it has not been done yet, you should:
switch to compatibility lever 120
rebuild indexes
update statistics
clear plan cache and force stored procedures recompile

SQL Server: stored procedure become very slow, raw SQL query is still very fast

We are struggling with a strange problem: a stored procedure become extremely slow when raw SQL is executed fairly fast.
We have
SQL Server 2008 R2 Express Edition SP1 10.50.2500.0 with several databases on it.
a database (it's size is around 747Mb)
a stored procedure which takes different parameters and does select among multiple tables from the database.
Code:
ALTER Procedure [dbo].[spGetMovieShortDataList](
#MediaID int = null,
#Rfa nvarchar(8) = null,
#LicenseWindow nvarchar(8) = null,
#OwnerID uniqueidentifier = null,
#LicenseType nvarchar(max) = null,
#PriceGroupID uniqueidentifier = null,
#Format nvarchar(max) = null,
#GenreID uniqueidentifier = null,
#Title nvarchar(max) = null,
#Actor nvarchar(max) = null,
#ProductionCountryID uniqueidentifier = null,
#DontReturnMoviesWithNoLicense bit = 0,
#DontReturnNotReadyMovies bit = 0,
#take int = 10,
#skip int = 0,
#order nvarchar(max) = null,
#asc bit = 1)
as
begin
declare #SQLString nvarchar(max);
declare #ascending nvarchar(5);
declare #ParmDefinition nvarchar(max);
set #ParmDefinition = '#MediaID int,
declare #now DateTime;
declare #Rfa nvarchar(8),
#LicenseWindow nvarchar(8),
#OwnerID uniqueidentifier,
#LicenseType nvarchar(max),
#PriceGroupID uniqueidentifier,
#Format nvarchar(max),
#GenreID uniqueidentifier,
#Title nvarchar(max),
#Actor nvarchar(max),
#ProductionCountryID uniqueidentifier,
#DontReturnMoviesWithNoLicense bit = 0,
#DontReturnNotReadyMovies bit = 0,
#take int,
#skip int,
#now DateTime';
set #ascending = case when #asc = 1 then 'ASC' else 'DESC' end
set #now = GetDate();
set #SQLString = 'SELECT distinct m.ID, m.EpisodNo, m.MediaID, p.Dubbed, pf.Format, t.OriginalTitle into #temp
FROM Media m
inner join Asset a1 on m.ID=a1.ID
inner join Asset a2 on a1.ParentID=a2.ID
inner join Asset a3 on a2.ParentID=a3.ID
inner join Title t on t.ID = a3.ID
inner join Product p on a2.ID = p.ID
left join AssetReady ar on ar.AssetID = a1.ID
left join License l on l.ProductID=p.ID
left join ProductFormat pf on pf.ID = p.Format '
+ CASE WHEN #PriceGroupID IS NOT NULL THEN
'left join LicenseToPriceGroup lpg on lpg.LicenseID = l.ID ' ELSE '' END
+ CASE WHEN #Title IS NOT NULL THEN
'left join LanguageAsset la on la.AssetID = m.ID ' ELSE '' END
+ CASE WHEN #LicenseType IS NOT NULL THEN
'left join LicenseType lt on lt.ID=l.LicenseTypeID ' ELSE '' END
+ CASE WHEN #Actor IS NOT NULL THEN
'left join Cast c on c.AssetID = a1.ID ' ELSE '' END
+ CASE WHEN #GenreID IS NOT NULL THEN
'left join ListToCountryToAsset lca on lca.AssetID=a1.ID ' ELSE '' END
+ CASE WHEN #ProductionCountryID IS NOT NULL THEN
'left join ProductionCountryToAsset pca on pca.AssetID=t.ID ' ELSE '' END
+
'where (
1 = case
when #Rfa = ''All'' then 1
when #Rfa = ''Ready'' then ar.Rfa
when #Rfa = ''NotReady'' and (l.TbaWindowStart is null OR l.TbaWindowStart = 0) and ar.Rfa = 0 and ar.SkipRfa = 0 then 1
when #Rfa = ''Skipped'' and ar.SkipRfa = 1 then 1
end) '
+
CASE WHEN #LicenseWindow IS NOT NULL THEN
'AND
1 = (case
when (#LicenseWindow = 1 And (l.WindowEnd < #now and l.TbaWindowEnd = 0)) then 1
when (#LicenseWindow = 2 And (l.TbaWindowStart = 0 and l.WindowStart < #now and (l.TbaWindowEnd = 1 or l.WindowEnd > #now))) then 1
when (#LicenseWindow = 4 And ((l.TbaWindowStart = 1 or l.WindowStart > #now) and (l.TbaWindowEnd = 1 or l.WindowEnd > #now))) then 1
when (#LicenseWindow = 3 And ((l.WindowEnd < #now and l.TbaWindowEnd = 0) or (l.TbaWindowStart = 0 and l.WindowStart < #now and (l.TbaWindowEnd = 1 or l.WindowEnd > #now)))) then 1
when (#LicenseWindow = 5 And ((l.WindowEnd < #now and l.TbaWindowEnd = 0) or ((l.TbaWindowStart = 1 or l.WindowStart > #now) and (l.TbaWindowEnd = 1 or l.WindowEnd > #now)))) then 1
when (#LicenseWindow = 6 And ((l.TbaWindowStart = 0 and l.WindowStart < #now and (l.TbaWindowEnd = 1 or l.WindowEnd > #now)) or ((l.TbaWindowStart = 1 or l.WindowStart > #now) and (l.TbaWindowEnd = 1 or l.WindowEnd > #now)))) then 1
when ((#LicenseWindow = 7 Or #LicenseWindow = 0) And ((l.WindowEnd < #now and l.TbaWindowEnd = 0) or (l.TbaWindowStart = 0 and l.WindowStart < #now and (l.TbaWindowEnd = 1 or l.WindowEnd > #now)) or ((l.TbaWindowStart = 1 or l.WindowStart > #now) and (l.TbaWindowEnd = 1 or l.WindowEnd > #now)))) then 1
end) ' ELSE '' END
+ CASE WHEN #OwnerID IS NOT NULL THEN
'AND (l.OwnerID = #OwnerID) ' ELSE '' END
+ CASE WHEN #MediaID IS NOT NULL THEN
'AND (m.MediaID = #MediaID) ' ELSE '' END
+ CASE WHEN #LicenseType IS NOT NULL THEN
'AND (lt.Name = #LicenseType) ' ELSE '' END
+ CASE WHEN #PriceGroupID IS NOT NULL THEN
'AND (lpg.PriceGroupID = #PriceGroupID) ' ELSE '' END
+ CASE WHEN #Format IS NOT NULL THEN
'AND (pf.Format = #Format) ' ELSE '' END
+ CASE WHEN #GenreID IS NOT NULL THEN
'AND (lca.ListID = #GenreID) ' ELSE '' END
+ CASE WHEN #DontReturnMoviesWithNoLicense = 1 THEN
'AND (l.ID is not null) ' ELSE '' END
+ CASE WHEN #Title IS NOT NULL THEN
'AND (t.OriginalTitle like N''%' + #Title + '%'' OR la.LocalTitle like N''%' + #Title + '%'') ' ELSE '' END
+ CASE WHEN #Actor IS NOT NULL THEN
'AND (rtrim(ltrim(replace(c.FirstName + '' '' + c.MiddleName + '' '' + c.LastName, '' '', '' ''))) like ''%'' + rtrim(ltrim(replace(#Actor,'' '','' ''))) + ''%'') ' ELSE '' END
+ CASE WHEN #DontReturnNotReadyMovies = 1 THEN
'AND ((ar.ID is not null) AND (ar.Ready = 1) AND (ar.CountryID = l.CountryID))' ELSE '' END
+ CASE WHEN #ProductionCountryID IS NOT NULL THEN
'AND (pca.ProductionCountryID = #ProductionCountryID)' ELSE '' END
+
'
select #temp.* ,ROW_NUMBER() over (order by ';
if #order = 'Title'
begin
set #SQLString = #SQLString + 'OriginalTitle';
end
else if #order = 'MediaID'
begin
set #SQLString = #SQLString + 'MediaID';
end
else
begin
set #SQLString = #SQLString + 'ID';
end
set #SQLString = #SQLString + ' ' + #ascending + '
) rn
into #numbered
from #temp
declare #count int;
select #count = MAX(#numbered.rn) from #numbered
while (#skip >= #count )
begin
set #skip = #skip - #take;
end
select ID, MediaID, EpisodNo, Dubbed, Format, OriginalTitle, #count TotalCount from #numbered
where rn between #skip and #skip + #take
drop table #temp
drop table #numbered';
execute sp_executesql #SQLString,#ParmDefinition, #MediaID, #Rfa, #LicenseWindow, #OwnerID, #LicenseType, #PriceGroupID, #Format, #GenreID,
#Title, #Actor, #ProductionCountryID, #DontReturnMoviesWithNoLicense,#DontReturnNotReadyMovies, #take, #skip, #now
end
The stored procedure was working pretty good and fast (it's execution usually took 1-2 seconds).
Example of call
DBCC FREEPROCCACHE
EXEC value = [dbo].[spGetMovieShortDataList]
#LicenseWindow =N'1',
#Rfa = N'NotReady',
#DontReturnMoviesWithNoLicense = False,
#DontReturnNotReadyMovies = True,
#take = 20,
#skip = 0,
#asc = False,
#order = N'ID'
Basically during execution of the stored procedure the executed 3 SQL queries, the first Select Into query takes 99% of time.
This query is
declare #now DateTime;
set #now = GetDate();
SELECT DISTINCT
m.ID, m.EpisodNo, m.MediaID, p.Dubbed, pf.Format, t.OriginalTitle
FROM Media m
INNER JOIN Asset a1 ON m.ID = a1.ID
INNER JOIN Asset a2 ON a1.ParentID = a2.ID
INNER JOIN Asset a3 ON a2.ParentID = a3.ID
INNER JOIN Title t ON t.ID = a3.ID
INNER JOIN Product p ON a2.ID = p.ID
LEFT JOIN AssetReady ar ON ar.AssetID = a1.ID
LEFT JOIN License l on l.ProductID = p.ID
LEFT JOIN ProductFormat pf on pf.ID = p.Format
WHERE
((l.TbaWindowStart is null OR l.TbaWindowStart = 0)
and ar.Rfa = 0 and ar.SkipRfa = 0)
And (l.WindowEnd < #now and l.TbaWindowEnd = 0 )
AND ((ar.ID is not null) AND (ar.Ready = 1) AND (ar.CountryID = l.CountryID))
This stored procedure, after massive data update on the database (a lot tables and rows were affected by the update, however DB size was almost unchanged, now it is 752 ) become to work extremely slow. Now it takes from 20 to 90 seconds.
If I take raw SQL query from the stored procedure - it is executed within 1-2 seconds.
We've tried:
the stored procedure is created with parameters
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
recreate the stored procedure with parameter with recompile
execute the stored procedure after purging prod cache DBCC FREEPROCCACHE
move part of where clauses into the join part
reindex tables
update statistics for the tables from the query using statements like UPDATE STATISTICS Media WITH FULLSCAN
However the execution of the stored procedure is still >> 30 seconds.
But if I run the SQL query which is generated by the SP - it is executed for less than 2 seconds.
I've compared execution plans for SP and for the raw SQL - they are quite different. During execution of RAW SQL - the optimizer is using Merge Joins, but when we execute SP - it uses Hash Match (Inner Join), like there are no indexes.
Execution Plan for RAW SQl - Fast
Execution Plan for SP - Slow
If someone knows what could it be - please help. Thanks in advance!
Try using using the hint OPTIMIZE FOR UNKNOWN. If it works, this may be better than forcing a recompile every time. The problem is that, the most efficient query plan depends on the actual value of the date paramter being supplied. When compiling the SP, sql server has to make a guess on what actual values will be supplied, and it is likely making the wrong guess here. OPTIMIZE FOR UNKNOWN is meant for this exact problem.
At the end of your query, add
OPTION (OPTIMIZE FOR (#now UNKNOWN))
http://blogs.msdn.com/b/sqlprogrammability/archive/2008/11/26/optimize-for-unknown-a-little-known-sql-server-2008-feature.aspx
Since you are using sp_executesql recompiling the procedure, or clearing the cached plan for the procedure won't actually help, the query plan for the query executed via sp_executesql
is cached separately to the stored procedure.
You either need to add the query hint WITH (RECOMPILE) to the sql executed, or clear the cache for that specific sql before executing it:
DECLARE #PlanHandle VARBINARY(64);
SELECT #PlanHandle = cp.Plan_Handle
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS st
WHERE st.text LIKE '%' + #SQLString;
DBCC FREEPROCCACHE (#PlanHandle); -- CLEAR THE CACHE FOR THIS QUERY
EXECUTE sp_executesql #SQLString,#ParmDefinition, #MediaID, #Rfa, #LicenseWindow, #OwnerID, #LicenseType, #PriceGroupID, #Format, #GenreID,
#Title, #Actor, #ProductionCountryID, #DontReturnMoviesWithNoLicense,#DontReturnNotReadyMovies, #take, #skip, #now;
This is of course irrelevant if when you executed DBCC FREEPROCCACHE you didn't pass any parameters and cleared the whole cache.
OPTIMIZE FOR (#parameter1 UNKNOWN, #parameter2 UNKNOWN,...)
worked wonders for me. I had exactly the same problem. I did not use any of the other hints or even: WITH (RECOMPILE)

Join unique ID's from another table

Here is the story: I have to implement filter. And in this filter there are certain categories I filter by.
One of the filters is "favourite" filter (#includeFavourites ).
I have this huge SQL with paging and sorting and everything.
Now, when "includeFavourites" option in filter is clicked, then I also have to select unique ID's from different table (this entries are stored in different datatable), where favourites are stored.
I have tried left outer join, but it returns "number of favourites" records for each record in primary table. Coalesce didn't help at all.
Here is my SQL:
--this is needed because stored procedure must know how many days are selected
DECLARE #daysCount int
SET #daysCount = 0
IF (#mon IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#tue IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#wed IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#thu IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#fri IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#sat IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#sun IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
-- Insert statements for procedure here
SELECT * FROM (
SELECT ROW_NUMBER() OVER
(
ORDER BY
CASE WHEN #OrderBy = 'ND' THEN title END DESC,
CASE WHEN #OrderBy = 'NA' THEN title END,
CASE WHEN #OrderBy = '' THEN title END,
CASE WHEN #OrderBy = 'RD' THEN authorRating END DESC,
CASE WHEN #OrderBy = 'RA' THEN authorRating
) AS Row,
Articles.ArticleId, Articles.userId, Articles.timestamp as datePosted, users.screenName,
defaultSmallImagePath, authorRating, ArticleCosts, title,
FROM Articles
LEFT OUTER JOIN
Users on Articles.userId = Users.userId
LEFT OUTER JOIN
ArticleAdditionalInformation ON ArticleAdditionalInformation.ArticleId = Articles.ArticleId
--JOIN FOR CONTINENT
LEFT OUTER JOIN
Codings as Continent ON Continent.codingKeyId = ArticleAdditionalInformation.continentId AND Continent.languageId = #languageId
-- JOIN FOR COUNTRY
LEFT OUTER JOIN
CodingsAssociated as Country ON Country.codingKeyId = ArticleAdditionalInformation.countryId AND Country.languageId = #languageId
-- JOIN FOR Article TRANSLATION DATA
LEFT OUTER JOIN
ArticlesTranslations ON ArticlesTranslations.ArticleId = Articles.ArticleId AND ArticlesTranslations.languageId=#languageId
LEFT OUTER JOIN
ArticleCategories ON ArticleCategories.ArticleId = Articles.ArticleId
WHERE
(
ArticleCategories.categorieId =1 OR ArticleCategories.categorieId =2 OR
ArticleCategories.categorieId =3 OR ArticleCategories.categorieId =4 OR
ArticleCategories.categorieId = 5
) AND
(ArticlesTranslations.title LIKE '%' + #searchString + '%' OR #searchString IS NULL)
-- COST filter
AND
(ArticleCosts < #cost OR #cost = 0)
AND
(ArticleCosts > 0 OR #cost = 0)
--END cost filter
-- EXCLUDE already stored for selected days
AND Articles.ArticleId -- exclude these ArticleIds
NOT IN
(
SELECT DailyContent.ArticleId
FROM DailyContent
WHERE
sectionId=#sectionId AND
(
weekDayId=#mon OR
weekDayId=#tue OR
weekDayId=#wed OR
weekDayId=#thu OR
weekDayId=#fri OR
weekDayId=#sat OR
weekDayId=#sun
)
GROUP BY
DailyContent.ArticleId
HAVING
(COUNT(sectionId) = #daysCount)
)
-- END exclude
) p
WHERE (Row > #startRowIndex AND Row <=#startRowIndex + #pageSize)
ORDER BY Row
END
So, I would only like to include unique articleIds from favourite table, when #includeFavourites parameter is not null.
Any hint would be greatly appreciated ;)
I am using SQL server 2008.
Try this one -
DECLARE #daysCount INT
SELECT #daysCount =
ISNULL(#mon, 0) + -- if #mon = 1, #tue = 2, .... 1 + (2-1)=1 + (3-2)=1 + ...
ISNULL(#tue - 1, 0) +
ISNULL(#wed - 2, 0) +
ISNULL(#thu - 3, 0) +
ISNULL(#fri - 4, 0) +
ISNULL(#sat - 5, 0) +
ISNULL(#sun - 6, 0)
SELECT *
FROM (
SELECT ROW_NUMBER() OVER
(
ORDER BY
CASE WHEN #OrderBy = 'ND' THEN title END DESC,
CASE WHEN #OrderBy IN ('NA', '') THEN title END,
CASE WHEN #OrderBy = 'RD' THEN authorRating END DESC,
CASE WHEN #OrderBy = 'RA' THEN authorRating
) AS [Row]
, a.ArticleId
, a.userId
, a.[timestamp] as datePosted
, u.screenName
, defaultSmallImagePath
, authorRating
, ArticleCosts
, title
FROM dbo.Articles a -- always use schema and alias
LEFT JOIN dbo.Users u on a.userId = u.userId -- OUTER is unnecessary
LEFT JOIN dbo.ArticleAdditionalInformation aai ON aai.ArticleId = a.ArticleId
LEFT JOIN dbo.Codings cd ON cd.codingKeyId = aai.continentId AND cd.languageId = #languageId
LEFT JOIN dbo.CodingsAssociated c ON c.codingKeyId = aai.countryId AND c.languageId = #languageId
LEFT JOIN dbo.ArticlesTranslations at ON at.ArticleId = a.ArticleId AND at.languageId = #languageId
LEFT JOIN dbo.ArticleCategories ac ON ac.ArticleId = a.ArticleId
WHERE ac.categorieId IN (1, 2, 3, 4, 5)
AND (
at.title LIKE '%' + #searchString + '%'
OR
#searchString IS NULL
)
AND (ArticleCosts < #cost OR #cost = 0)
AND (ArticleCosts > 0 OR #cost = 0)
AND a.ArticleId NOT IN (
SELECT dc2.ArticleId
FROM dbo.DailyContent dc2
WHERE sectionId = #sectionId
AND (
weekDayId % #daysCount = 0 -- possible it's works
--weekDayId = #mon OR
--weekDayId = #tue OR
--weekDayId = #wed OR
--weekDayId = #thu OR
--weekDayId = #fri OR
--weekDayId = #sat OR
--weekDayId = #sun
)
GROUP BY dc2.ArticleId
HAVING COUNT(sectionId) = #daysCount
)
) p
WHERE [Row] BETWEEN #startRowIndex AND #startRowIndex + #pageSize
--ORDER BY [Row] -- ROW_COUNT already sorted your rows