SELECT COUNT(foreign ID) for each row in datatable - sql

I have datable where I store my dailyContent selection.
This is different for each day.
When I select more then one day, then I need to return items, which are the same for all days.
I have tried something like this:
SELECT * FROM
(
SELECT
( -- For count
SELECT COUNT(recipeId) AS [Count]
FROM DailyContentDish
WHERE
(
(weekDayId=#mon OR #mon IS NULL) OR
(weekDayId=#tue OR #tue IS NULL) OR
(weekDayId=#wed OR #wed IS NULL) OR
(weekDayId=#thu OR #thu IS NULL) OR
(weekDayId=#fri OR #fri IS NULL) OR
(weekDayId=#sat OR #sat IS NULL) OR
(weekDayId=#sun OR #sun IS NULL)
)
GROUP BY DailyContentDish.recipeId
) AS cnt,
-- End for count
DailyContentDish.dailyContentDishId,
DailyContentDish.recipeId AS Rec,
title,
150 AS calories,
defaultSmallImagePath,
activePreparationTime + passivePreparationTime AS overallPreparationTime,
CAST(
CASE WHEN EXISTS
(
SELECT DailyContentDishFavourite.dailyContentDishFavouriteId
FROM DailyContentDishFavourite
WHERE DailyContentDishFavourite.dailyContentDishId = DailyContentDish.dailyContentDishId
)
THEN 1
ELSE 0
END
AS BIT) AS isFavouriteWhenGeneratingMenu
FROM DailyContentDish
LEFT OUTER JOIN
RecipesTranslations ON RecipesTranslations.recipeId = DailyContentDish.recipeId
LEFT OUTER JOIN
RecipeAdditionalInformation ON RecipeAdditionalInformation.recipeId = DailyContentDish.recipeId
WHERE
isEnabled = 1 AND
mealId=#mealId AND
(
weekDayId=#mon OR
weekDayId=#tue OR
weekDayId=#wed OR
weekDayId=#thu OR
weekDayId=#fri OR
weekDayId=#sat OR
weekDayId=#sun
)
) p
WHERE p.cnt = #daysCount
The problem is, that nested select which should return count returns it for all rows, not just one entry (each row, that is).
Since entries with recipeId are entered more then once I would like to know how many times are they entered.
SELECT
( -- For count
SELECT COUNT(recipeId) AS [Count]
FROM DailyContentDish
WHERE
(
(weekDayId=#mon OR #mon IS NULL) OR
(weekDayId=#tue OR #tue IS NULL) OR
(weekDayId=#wed OR #wed IS NULL) OR
(weekDayId=#thu OR #thu IS NULL) OR
(weekDayId=#fri OR #fri IS NULL) OR
(weekDayId=#sat OR #sat IS NULL) OR
(weekDayId=#sun OR #sun IS NULL)
) AND Something should be here (I guess)
GROUP BY DailyContentDish.recipeId
) AS cnt,
-- End for count
This part should return COUNT of entries for each row I select - but it retuns me COUNT of all entries.
Or should I take a different path with this.
Any hint is greatly appreciated.
I am using MS SQL server 2008
EDIT:
this is whole stored procedure:
#userId int,
#languageId int,
#mealId int,
#mon int,
#tue int,
#wed int,
#thu int,
#fri int,
#sat int,
#sun int,
#orderBy nvarchar(2),
#pageSize int,
#startRowIndex int
AS
BEGIN
SET NOCOUNT ON;
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
(
SELECT [Count] = COUNT(recipeId)
FROM dbo.DailyContentDish d
WHERE
(
ISNULL(#mon, weekDayId) = weekDayId OR
ISNULL(#tue, weekDayId) = weekDayId OR
ISNULL(#wed, weekDayId) = weekDayId OR
ISNULL(#thu, weekDayId) = weekDayId OR
ISNULL(#fri, weekDayId) = weekDayId OR
ISNULL(#sat, weekDayId) = weekDayId OR
ISNULL(#sun, weekDayId) = weekDayId
)
GROUP BY d.recipeId
) AS cnt,
d.dailyContentDishId,
d.recipeId AS Rec,
title,
150 AS calories,
defaultSmallImagePath,
activePreparationTime + passivePreparationTime AS overallPreparationTime,
CASE WHEN d2.dailyContentDishId IS NULL THEN 1 ELSE 0 END AS isFavouriteWhenGeneratingMenu
FROM dbo.DailyContentDish d
LEFT JOIN dbo.RecipesTranslations r ON r.recipeId = d.recipeId
LEFT JOIN dbo.RecipeAdditionalInformation t ON t.recipeId = d.recipeId
LEFT JOIN dbo.DailyContentDishFavourite d2 ON d.dailyContentDishId = d2.dailyContentDishId
WHERE isEnabled = 1
AND mealId = #mealId
AND (
weekDayId = #mon OR
weekDayId = #tue OR
weekDayId = #wed OR
weekDayId = #thu OR
weekDayId = #fri OR
weekDayId = #sat OR
weekDayId = #sun
)
) p
WHERE p.cnt = #daysCount
Edit1: I have uploaded diagram:
Here is sample data (for meal Id = 1, this is also selected on form), explanation:
- recipe with ID 125 will be present on Monday (weekDayId = 1) and Saturday (weekDayId = 7). So, this recipe must be returned if I select only Monday OR if I select only Saturday OR if I select Monday and Saturday. If I also select any other day then ithis record is not returned.
- recipe with ID 105 must be returned when weekDays 1, 6 and 7 (Monday, Saturday, Sunday) are selected. Same as above, if any other day is selected then this record is not returned.

Possible this help you -
ALTER PROCEDURE dbo.usp_GetDailyContentDish
#userId INT,
#languageId INT,
#mealId INT,
#mon INT,
#tue INT,
#wed INT,
#thu INT,
#fri INT,
#sat INT,
#sun INT,
#orderBy NVARCHAR(2),
#pageSize INT,
#startRowIndex INT
AS BEGIN
SET NOCOUNT ON;
DECLARE #daysCount INT
SELECT #daysCount =
CASE WHEN #mon IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN #tue IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN #wed IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN #thu IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN #fri IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN #sat IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN #sun IS NOT NULL THEN 1 ELSE 0 END
SELECT
Rec
, calories
, overallPreparationTime
, isFavouriteWhenGeneratingMenu
FROM (
SELECT
(
SELECT [Count] = COUNT(d3.recipeId)
FROM dbo.DailyContentDish d3
WHERE
(
ISNULL(#mon, weekDayId) = weekDayId OR
ISNULL(#tue, weekDayId) = weekDayId OR
ISNULL(#wed, weekDayId) = weekDayId OR
ISNULL(#thu, weekDayId) = weekDayId OR
ISNULL(#fri, weekDayId) = weekDayId OR
ISNULL(#sat, weekDayId) = weekDayId OR
ISNULL(#sun, weekDayId) = weekDayId
) AND d3.recipeId = d.recipeId
GROUP BY d3.recipeId
) AS cnt,
d.dailyContentDishId,
d.recipeId AS Rec,
title,
150 AS calories,
defaultSmallImagePath,
activePreparationTime + passivePreparationTime AS overallPreparationTime,
CASE WHEN d2.dailyContentDishId IS NULL THEN 1 ELSE 0 END AS isFavouriteWhenGeneratingMenu
FROM dbo.DailyContentDish d
LEFT JOIN dbo.RecipesTranslations r ON r.recipeId = d.recipeId
LEFT JOIN dbo.RecipeAdditionalInformation t ON t.recipeId = d.recipeId
LEFT JOIN dbo.DailyContentDishFavourite d2 ON d.dailyContentDishId = d2.dailyContentDishId
WHERE isEnabled = 1
AND mealId = #mealId
AND (
weekDayId = #mon OR
weekDayId = #tue OR
weekDayId = #wed OR
weekDayId = #thu OR
weekDayId = #fri OR
weekDayId = #sat OR
weekDayId = #sun
)
) p
WHERE p.cnt = #daysCount
END
Small off-top:
This:
AND (
weekDayId = #mon OR
weekDayId = #tue OR
weekDayId = #wed OR
weekDayId = #thu OR
weekDayId = #fri OR
weekDayId = #sat OR
weekDayId = #sun
)
Possible optimize to this:
weekDayId % #weekDay = 0
If #mon, #tue is not null and contains 1, 2, ...

SELECT *
FROM (
SELECT
( -- For count
SELECT COUNT(d.recipeId) AS [Count]
FROM DailyContentDish d
WHERE (
ISNULL(#amon, d.weekDayId) = d.weekDayId OR
ISNULL(#tue, d.weekDayId) = d.weekDayId OR
ISNULL(#wed, d.weekDayId) = d.weekDayId OR
ISNULL(#thu, d.weekDayId) = d.weekDayId OR
ISNULL(#fri, d.weekDayId) = d.weekDayId OR
ISNULL(#sat, d.weekDayId) = d.weekDayId OR
ISNULL(#sun, d.weekDayId) = d.weekDayId
) AND d.recipeId = DailyContentDish.recipeId
GROUP BY d.recipeId
) AS cnt,
-- End for count
DailyContentDish.dailyContentDishId,
DailyContentDish.recipeId AS Rec,
title,
150 AS calories,
defaultSmallImagePath,
activePreparationTime + passivePreparationTime AS overallPreparationTime,
CAST(
CASE WHEN EXISTS
(
SELECT DailyContentDishFavourite.dailyContentDishFavouriteId
FROM DailyContentDishFavourite
WHERE DailyContentDishFavourite.dailyContentDishId = DailyContentDish.dailyContentDishId
)
THEN 1
ELSE 0
END
AS BIT) AS isFavouriteWhenGeneratingMenu
FROM DailyContentDish
LEFT OUTER JOIN
RecipesTranslations ON RecipesTranslations.recipeId = DailyContentDish.recipeId
LEFT OUTER JOIN
RecipeAdditionalInformation ON RecipeAdditionalInformation.recipeId = DailyContentDish.recipeId
WHERE
isEnabled = 1 AND
mealId=#mealId AND
(
weekDayId=#mon OR
weekDayId=#tue OR
weekDayId=#wed OR
weekDayId=#thu OR
weekDayId=#fri OR
weekDayId=#sat OR
weekDayId=#sun
)
) p
WHERE p.cnt = #daysCount
UPDATE 21.05.2013(added Demo)
IF OBJECT_ID('tempdb.dbo.#weekDays') IS NOT NULL DROP TABLE dbo.#weekDays
SELECT weekDayId
INTO dbo.#weekDays
FROM(VALUES(#mon),
(#tue),
(#wed),
(#thu),
(#fri),
(#sat),
(#sun))x(weekDayId)
WHERE weekDayId IS NOT NULL
CREATE UNIQUE CLUSTERED INDEX x ON dbo.#weekDays(weekDayId)
SELECT d.dailyContentDishId,
d.recipeId AS Rec,
title,
150 AS calories,
defaultSmallImagePath,
activePreparationTime + passivePreparationTime AS overallPreparationTime,
CASE WHEN f.dailyContentDishId IS NULL THEN 1 ELSE 0 END AS isFavouriteWhenGeneratingMen
FROM DailyContentDish d
LEFT JOIN RecipesTranslations ON RecipesTranslations.recipeId = d.recipeId
LEFT JOIN RecipeAdditionalInformation ON RecipeAdditionalInformation.recipeId = d.recipeId
LEFT JOIN dbo.DailyContentDishFavourite f ON d.dailyContentDishId = f.dailyContentDishId
WHERE d.isEnabled = 1 AND d.mealId = #mealId
AND NOT EXISTS(
SELECT d3.weekDayId
FROM dbo.#weekDays d3
EXCEPT
SELECT d2.WeekDayId
FROM DailyContentDish d2
WHERE d.recipeId = d2.recipeId
AND d2.isEnabled = 1 AND d2.mealId = #mealId
)
Simple demo on SQLFiddle

only meals which are the same for that days (and meals) should be
returned
What is missing is the correlation of the outer query to the count calculation in your inner query. I.e. the following:
( DC1.WeekDayId In( #Mon, #Tue, #Wed, #Thu, #Fri, #Sat, #Sun )
Or Coalesce( #Mon, #Tue, #Wed, #Thu, #Fri, #Sat, #Sun ) Is Null )
And DC1.MealId = DC.MealId
You need to alias at least one of the tables to make this happen. Typically, it is easier to read if you alias the tables on both the inner and outer query. The other item missing is that the seven variables for each day represent ticks ("select this day") instead of the day itself. If we change that, it makes the query simpler.
Select #Mon = Case When #Mon Is Not Null Then 1 End
, #Tue = Case When #Tue Is Not Null Then 2 End
, #Wed = Case When #Wed Is Not Null Then 3 End
, #Thu = Case When #Thu Is Not Null Then 4 End
, #Fri = Case When #Fri Is Not Null Then 5 End
, #Sat = Case When #Sat Is Not Null Then 6 End
, #Sun = Case When #Sun Is Not Null Then 7 End;
Select Count(*) Over() As CountOfResults
, (
Select Count(*)
From DailyContentDish As DC1
Where DC1.weekDayId = DC.weekDayId
) As CountOfDishesOnDay
, (
Select Count(Distinct mealId)
From DailyContentDish As DC1
Where DC1.weekDayId = DC.weekDayId
) As CountOfMeals
, DC.DailyContentDishId
, DC.RecipeId As Rec
, Title
, 150 As Calories
, DefaultsMallImagePath
, ActivePreparationTime
+ PassivePreparationTime As OverallPreparationTime
, Cast (
Case
When Exists (
Select 1
From DailyContentDishFavourite As DF1
Where DF1.DailyContentDishId = DC.DailyContentDishId
) Then 1
Else 0
End
As Bit) As IsFavouriteWhenGeneratingMenu
From DailyContentDish As DC
Left Join RecipesTranslations As RT
On RT.RecipeId = DC.RecipeId
Left Join RecipeAdditionalInformation As RA
On RA.RecipeId = DC.RecipeId
Where DC.IsEnabled = 1
And DC.MealId=#MealId
And DC.WeekDayId In( #Mon, #Tue, #Wed, #Thu, #Fri, #Sat, #Sun )
Addition
If the daily variables are supposed to represent a count of results per day returned (e.g., if #Mon = 2, then we should get back two rows for Monday), then you could do something like so:
Declare #DailyParameters Table
(
DayCount int not null
, DayOfWeek int not null
)
Insert #DailyParameters( DayCount, DayOfWeek )
Select Z.Cnt, Z.DayOfWeek
From (
Select #Mon As Cnt, 1 As DayOfWeek
Union All Select #Tue, 2
Union All Select #Wed, 3
Union All Select #Thu, 4
Union All Select #Fri, 5
Union All Select #Sat, 6
Union All Select #Sun, 7
) As Z
Where Z.Cnt Is Not Null
The Where clause would then change to something like so:
Where DC.IsEnabled = 1
And DC.MealId = #MealId
And DC.WeekDayId In( Select DayOfWeek From #DailyParameters )
And (
Select Count(*)
From DailyContentDish As DC1
Where DC1.weekDayId = DC.weekDayId
) = (
Select D1.DayCount
From #DailyParameters As D1
Where D1.DayOfWeek = DC.weekDayId
)

"Since entries with recipeId are entered more then once I would like to know how many times are they entered."
Base on this statement I would just use the OVER clause with COUNT.
Something like:
SELECT
COUNT(*) OVER (PARTITION BY recipeId) AS 'cnt'
FROM DailyContentDish
I would need more details about the tables and what the output should be in order to provide more details.
Here is more info on the OVER clause in 2008: http://msdn.microsoft.com/en-us/library/ms189461(v=sql.105).aspx
Example using COUNT with OVER: http://blog.sqlauthority.com/2011/08/11/sql-server-tips-from-the-sql-joes-2-pros-development-series-advanced-aggregates-with-the-over-clause-day-11-of-35/

Related

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

Catch All Queries with a Table Valued Function

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)

Query optimization. Duplicate subqueries

We found a slow query in our legacy system. What I see in the query is a duplicate fragment. Here's the full query:
DECLARE #SellerId INT;
DECLARE #DateFrom DATETIME;
DECLARE #DateTo DATETIME;
SET #SellerId = 5396884;
SET #DateFrom = '2016-01-05';
SET #DateTo = '2016-10-08';
DECLARE #CurrentDate DATETIME;
SET #CurrentDate = GETDATE();
CREATE TABLE #ReportDate (codes INT, dates DATETIME);
DECLARE #dif as INT;
DECLARE #cont as INT;
DECLARE #currdate as DATETIME;
SET #dif = DATEDIFF(day, #DateFrom, #DateTo);
SET #cont = 1;
SET #currdate = #DateFrom - 1;
WHILE (#cont <= #dif + 1)
BEGIN
SET #currdate = DATEADD(DAY, 1, #currdate);
INSERT INTO #ReportDate VALUES (#cont, #currdate);
SET #cont = #cont + 1;
END
/* HOW TO OPTIMIZE THIS ONE? */
SELECT
#ReportDate.dates as valid_date,
(
SELECT
COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives
FROM
(
SELECT *
FROM salesView
WHERE
salesView.sell_id NOT IN
(
SELECT sell_id
FROM salesStates
WHERE
salesStates.aborted = 1
)
) nonCancelledSales
WHERE
nonCancelledSales.seller_id = #SellerId AND
nonCancelledSales.cancelled = 0 AND
nonCancelledSales.void = 0 AND
nonCancelledSales.hasDiscount = 0 AND
nonCancelledSales.dateOfSale <= #ReportDate.dates AND
nonCancelledSales.currentState = (SELECT MAX(hveest.date)
FROM salesStates hveest
WHERE
hveest.sell_id = nonCancelledSales.sell_id AND
hveest.date <= #ReportDate.dates) AND
nonCancelledSales.lastProductDate = (SELECT MAX(hvepro.date)
FROM productHistory hvepro
WHERE
hvepro.sell_id = nonCancelledSales.sell_id AND
hvepro.date <= #ReportDate.dates)
) total_actives,
(
SELECT
ISNULL(SUM(nonCancelledSales.paymentValue),0) as active
FROM
(
SELECT *
FROM salesView
WHERE
salesView.sell_id NOT IN
(
SELECT sell_id
FROM salesStates
WHERE
salesStates.aborted = 1
)
) nonCancelledSales
WHERE
nonCancelledSales.seller_id = #SellerId AND
nonCancelledSales.cancelled = 0 AND
nonCancelledSales.void = 0 AND
nonCancelledSales.hasDiscount = 0 AND
nonCancelledSales.dateOfSale <= #ReportDate.dates AND
nonCancelledSales.currentState = (SELECT MAX(hveest.date)
FROM salesStates hveest
WHERE
hveest.sell_id = nonCancelledSales.sell_id AND
hveest.date <= #ReportDate.dates) AND
nonCancelledSales.lastProductDate = (SELECT MAX(hvepro.date)
FROM productHistory hvepro
WHERE
hvepro.sell_id = nonCancelledSales.sell_id AND
hvepro.date <= #ReportDate.dates)
) active
FROM
#ReportDate
GROUP BY
#ReportDate.dates
DROP TABLE #ReportDate
Here are the two duplicated fragments I see:
(
SELECT
COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives
FROM
(
SELECT *
FROM salesView
WHERE
salesView.sell_id NOT IN
(
SELECT sell_id
FROM salesStates
WHERE
salesStates.aborted = 1
)
) nonCancelledSales
WHERE
nonCancelledSales.seller_id = #SellerId AND
nonCancelledSales.cancelled = 0 AND
nonCancelledSales.void = 0 AND
nonCancelledSales.hasDiscount = 0 AND
nonCancelledSales.dateOfSale <= #ReportDate.dates AND
nonCancelledSales.currentState = (SELECT MAX(hveest.date)
FROM salesStates hveest
WHERE
hveest.sell_id = nonCancelledSales.sell_id AND
hveest.date <= #ReportDate.dates) AND
nonCancelledSales.lastProductDate = (SELECT MAX(hvepro.date)
FROM productHistory hvepro
WHERE
hvepro.sell_id = nonCancelledSales.sell_id AND
hvepro.date <= #ReportDate.dates)
) total_actives,
(
SELECT
ISNULL(SUM(nonCancelledSales.paymentValue),0) as active
FROM
(
SELECT *
FROM salesView
WHERE
salesView.sell_id NOT IN
(
SELECT sell_id
FROM salesStates
WHERE
salesStates.aborted = 1
)
) nonCancelledSales
WHERE
nonCancelledSales.seller_id = #SellerId AND
nonCancelledSales.cancelled = 0 AND
nonCancelledSales.void = 0 AND
nonCancelledSales.hasDiscount = 0 AND
nonCancelledSales.dateOfSale <= #ReportDate.dates AND
nonCancelledSales.currentState = (SELECT MAX(hveest.date)
FROM salesStates hveest
WHERE
hveest.sell_id = nonCancelledSales.sell_id AND
hveest.date <= #ReportDate.dates) AND
nonCancelledSales.lastProductDate = (SELECT MAX(hvepro.date)
FROM productHistory hvepro
WHERE
hvepro.sell_id = nonCancelledSales.sell_id AND
hvepro.date <= #ReportDate.dates)
) active
Is it fully necessary to duplicate the query ? In the first one he's getting:
COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives
on the second one:
ISNULL(SUM(nonCancelledSales.paymentValue),0) as active
I suppose there has to be some way to rewrite the query but I'm not sure how.
You can combine these, if you use OUTER APPLY.
The idea is:
SELECT . . ., x.actives, x.active
FROM #ReportDate OUTER APPLY
(SELECT COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives,
COALESCE(SUM(nonCancelledSales.paymentValue), 0) as active
. . . -- rest of query here
) x;
In this case, OUTER APPLY is a lot like a correlated subquery in the FROM clause that can return multiple rows.

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

Improve case statement in order clause

I have the store sql
ALTER procedure [dbo].[TNNews_User_SearchBasic]
#Title nvarchar(400),
#CategoryId int,
#IsInterested int,
#IsHot int,
#IsTopCategory int,
#IsPublish int,
#PageSize int,
#PageIndex int,
#OrderBy varchar(20),
#PortalId int,
#LanguageId varchar(6)
as
DECLARE #EndTime DATETIME
DECLARE #StartTime DATETIME
SET #StartTime = GETDATE()
declare #tbCategory table(Id int)
DECLARE #StartRowIndex INT
IF #PageSize=0 SELECT #PageSize=count(*) FROM TNNews
IF(#PageIndex<0) SET #PageIndex=0
SET #StartRowIndex = #PageSize*(#PageIndex-1)+1
;WITH tmpCategory(Id, Name,ParentId,Level)
AS (
SELECT
e.Id,
e.Name,
e.ParentId,
1
FROM dbo.TNCategory AS e
WHERE
Id = #CategoryId or (#CategoryId='' and ParentId<=0)
UNION ALL
SELECT
e.Id,
e.Name,
e.ParentId,
Level + 1
FROM dbo.TNCategory AS e
JOIN tmpCategory AS d ON e.ParentId = d.Id
)
insert #tbCategory select Id from tmpCategory
;WITH tmpNews as
(
SELECT
a.Id,a.Title,a.Subject
,ROW_NUMBER() OVER (ORDER BY (Publisheddate) desc) as ThuTuBanGhi
FROM dbo.TNNews a
where 1 = 1
--and ( Title like '%'+#Title+'%')
and (#CategoryId = -1 or exists (select 0 from #tbCategory b where b.Id = a.CategoryId))
and (#IsInterested = -1 or IsIntrested = #IsInterested )
and (#IsHot = -1 or IsHot = #IsHot )
and (#IsTopCategory = -1 or IsTopCategory = #IsTopCategory )
and (#IsPublish = -1 or IsPublished = #IsPublish)
and PortalId=#PortalId
and LanguageId = #LanguageId
)
select *, (select COUNT(Id) from tmpNews) as 'TongSoBanGhi' from tmpNews
WHERE
ThuTuBanGhi BETWEEN (#StartRowIndex) AND (#StartRowIndex + #PageSize-1)
SET #EndTime = GETDATE()
PRINT 'StartTime = ' + CONVERT(VARCHAR(30),#StartTime,121)
PRINT ' EndTime = ' + CONVERT(VARCHAR(30),#EndTime,121)
PRINT ' Duration = ' + STR(DATEDIFF(MILLISECOND,#StartTime,#EndTime)) + ' millisecond'
select STR(DATEDIFF(MILLISECOND,#StartTime,#EndTime))
After this store excute
EXEC [dbo].[TNNews_User_SearchBasic]
#Title='',
#CategoryId = '',
#IsInterested = -1,
#IsHot = -1,
#IsTopCategory = -1,
#IsPublish = -1,
#PageSize = 20,
#PageIndex = 1,
#OrderBy = '',
#PortalId = 0,
#LanguageId = N'vi-VN'
go
The time excute about "200ms". And I create a new store "TNNews_User_SearchBasic1" with some change.
.....
--,ROW_NUMBER() OVER (ORDER BY (Publisheddate) desc) as ThuTuBanGhi
,ROW_NUMBER() OVER (ORDER BY (case when #OrderBy='VIEW_COUNT' then ViewCount else PublishedDate end) desc) as ThuTuBanGhi
.....
and now the time excute this store
EXEC [dbo].[TNNews_User_SearchBasic1]
#Title='',
#CategoryId = '',
#IsInterested = -1,
#IsHot = -1,
#IsTopCategory = -1,
#IsPublish = -1,
#PageSize = 20,
#PageIndex = 1,
#OrderBy = '',
#PortalId = 0,
#LanguageId = N'vi-VN'
GO
about 900ms.
I don't understand why there is a change. Please help me improve these stores.
PS: I put example db at: http://anhquan22.tk/Portals/0/Videos/web.rar
Finished analysis the structure of your database. The part of the problem is hiding in the table structure.
I have prepared a backup for you. In it, I slightly modified scheme to improve performance and some normalize the table. You can download it from this link.
...to your question, I would do like this -
DECLARE #SQL NVARCHAR(1000)
SELECT #SQL = N'
;WITH tmpCategory (Id, Name, ParentId, [Level]) AS
(
SELECT
e.Id
, e.Name
, e.ParentId
, 1
FROM dbo.TNCategory e
WHERE Id = #CategoryId OR (#CategoryId = '''' AND ParentId <= 0)
UNION ALL
SELECT
e.Id
, e.Name
, e.ParentId
, [Level] + 1
FROM dbo.TNCategory e
JOIN tmpCategory d ON e.ParentId = d.Id
)
SELECT
a.Id
, ROW_NUMBER() OVER (ORDER BY ' +
CASE WHEN #OrderBy = 'VIEW_COUNT'
THEN 'ViewCount'
ELSE 'PublishedDate'
END +' DESC) AS ThuTuBanGhi
FROM dbo.TNNewsMain a
where PortalId = #PortalId
AND LanguageId = #LanguageId'
+ CASE WHEN #IsInterested != -1 THEN ' AND IsInterested = #IsInterested' ELSE '' END
+ CASE WHEN #IsHot != -1 THEN ' AND IsHot = #IsHot' ELSE '' END
+ CASE WHEN #IsTopCategory != -1 THEN ' AND IsTopCategory = #IsTopCategory' ELSE '' END
+ CASE WHEN #IsPublish != -1 THEN ' AND IsPublish = #IsPublish' ELSE '' END
+ CASE WHEN #CategoryId != -1 THEN '' ELSE ' AND EXISTS(SELECT 1 FROM tmpCategory b WHERE b.Id = a.CategoryId)' END
INSERT INTO #temp (Id, ThuTuBanGhi)
EXECUTE sp_executesql
#SQL
, N'#PortalId INT
, #LanguageId VARCHAR(6)
, #CategoryId INT
, #IsInterested INT
, #IsHot INT
, #IsTopCategory INT
, #IsPublish INT'
, #PortalId = #PortalId
, #LanguageId = #LanguageId
, #CategoryId = #CategoryId
, #IsInterested = #IsInterested
, #IsHot = #IsHot
, #IsTopCategory = #IsTopCategory
, #IsPublish = #IsPublish;
SELECT
d.Id
, tm.Title
, tm.[Subject]
, d.ThuTuBanGhi
, c.TongSoBanGhi
FROM (
SELECT t.Id
, t.ThuTuBanGhi
FROM #temp t
WHERE t.ThuTuBanGhi BETWEEN #StartRowIndex AND #StartRowIndex + #PageSize - 1
) d
JOIN TNNewsMain tm ON d.Id = tm.Id
CROSS JOIN (
SELECT TongSoBanGhi = (SELECT COUNT(1) FROM #temp)
) c