Pagination over join table rows - sql

I have a SQL server request with several tables, for example:
Workorder
WorkorderOccurrence
Schedule
A workorder occurrence is a realisation of a specific schedled workorder
For workorder 1 scheduled every day I have:
Workorder occurrence 1_1 the first day
Workorder occurrence 1_2 the second day
For a workorder 2 scheduled every week I have:
Workorder occurrence 1_7
Workorder occurrence 2_1
Workorder occurence 1_8
And so ...
I have a pagination on the front for an agenda view, but the pagination must be done on workorder and not on the occurrence.
Consequently I would like to return the workorder occurrences (maybe 50, 100, 200,).
but on the 20 workorder request by the pagination. But it seems to eeturn the 20 workorder occurrence with the offset and I don't know how to do this.
Below my attempt:
CREATE FUNCTION [dbo].[FctGetWorkorderAgenda]
(
#SeverityIDsFilter NVARCHAR(MAX) = '',
#Culture NVARCHAR(MAX) = 'FR-fr',
#StartDate DATETIMEOFFSET(7),
#EndDate DATETIMEOFFSET(7),
#PageNumber INT = 0,
#ResultByPage INT = 50
)
RETURNS #resTable TABLE
(
[WorkorderID] INT NOT NULL,
[EndDate] DATETIMEOFFSET(0),
[Name] NVARCHAR(MAX),
[FixedNextDate] DATETIMEOFFSET(0),
[NextDate] DATETIMEOFFSET(0),
[WorkorderStatutType] SMALLINT NOT NULL,
[FrequenceType] SMALLINT NOT NULL,
[DayOfWeek] INT,
[DayOfMonth] INT,
[MonthType] INT,
[DayOfMonthType] INT,
[FrequencyTime] TIME(7) NOT NULL,
[FrequencyOffset] INT,
[VendorName] NVARCHAR(MAX) NOT NULL,
[EquipmentName] NVARCHAR(MAX) NOT NULL,
[OrganizationID] INT NOT NULL,
[WorkorderSeverity] INT NOT NULL,
[FullCount] INT NOT NULL
)
AS
BEGIN
INSERT INTO #resTableBooking (
WO.WorkorderID,
WO.EndDate,
WO.Name,
WOO.FixedNextDate,
WOO.NextDate,
WOO.WorkorderStatutType,
S.FrequenceType,
S.DayOfWeek,
S.DayOfMonth,
S.MonthType,
S.DayOfMonthType,
[FrequencyTime],
S.FrequencyOffset,
[EquipmentName],
[WorkorderSeverity],
[FullCount])
SELECT
WorkorderID,
EndDate,
Name,
FixedNextDate,
NextDate,
WorkorderStatutType,
FrequenceType,
DayOfWeek,
DayOfMonth,
MonthType,
DayOfMonthType,
FrequencyTime,
FrequencyOffset,
EquipmentName,
WorkorderSeverity,
FullCount
FROM (
SELECT
WO.WorkorderID,
WO.EndDate,
WO.Name,
WOO.FixedNextDate,
WOO.NextDate,
WOO.WorkorderStatutType,
S.FrequenceType,
S.DayOfWeek,
S.DayOfMonth,
S.MonthType,
S.DayOfMonthType,
S.Time AS FrequencyTime,
S.FrequencyOffset,
E.Name AS EquipmentName,
(
CASE
WHEN (WO.EndDate IS NOT NULL AND (WO.EndDate <= WO.CreatedDate OR WO.NextDate >= WO.EndDate))
THEN -5 -- WorkorderSeverity.Closed
WHEN (WO.NextDate <= WO.CreatedDate)
THEN -4 -- WorkorderSeverity.DeadlineLate
WHEN (S.FrequenceType = 3) -- FrequencyType.EveryMonth
THEN IIF(
DATEADD(day, -7, WO.NextDate) <= WO.CreatedDate,
-3 /* WorkorderSeverity.DeadlineWarning */,
-2 /* WorkorderSeverity.InTime */
)
WHEN (S.FrequenceType = 1 OR S.FrequenceType = 6)
THEN IIF(
DATEADD(month, -1, WO.NextDate) <= WO.CreatedDate,
-3 /* WorkorderSeverity.DeadlineWarning */,
-2 /* WorkorderSeverity.InTime */
)
WHEN (S.FrequenceType = 0) -- FrequencyType.None
THEN CASE
WHEN (WO.NextDate <= WO.CreatedDate) THEN -4 /* WorkorderSeverity.DeadlineLate */
WHEN (DATEADD(day, -3, WO.NextDate) <= WO.CreatedDate) THEN -3
ELSE -2
END
ELSE -2
END
) AS WorkorderSeverity,
COUNT(WO.WorkorderID) OVER() FullCount
FROM [dbo].[WorkorderOccurrence] WOO WITH(NOLOCK)
JOIN [dbo].[Workorder] WO WITH(NOLOCK) ON WO.WorkorderID = WOO.WorkorderID
JOIN [dbo].[Schedule] S WITH(NOLOCK) ON S.ScheduleID = WO.WorkorderScheduleID
JOIN [dbo].[Equipment] E WITH(NOLOCK) ON E.EquipmentID = WO.EquipmentID
LEFT JOIN dbo.Localization l WITH(NOLOCK) ON l.CultureKey = E.CultureKey AND l.CultureName = #culture
WHERE (WOO.FixedNextDate IS NOT NULL AND WOO.FixedNextDate BETWEEN #StartDate AND #EndDate
OR WOO.NextDate IS NOT NULL AND WOO.NextDate BETWEEN #StartDate AND #EndDate)
GROUP BY WO.WorkorderID, WO.EndDate, WO.Name, WO.CreatedDate, WO.NextDate,
WOO.NextDate, WOO.FixedNextDate, WOO.WorkorderOccurrenceID, WOO.WorkorderStatutType,
S.FrequenceType, S.DayOfWeek, S.DayOfMonth, S.MonthType, S.DayOfMonthType, S.Time, S.FrequencyOffset,
E.Name
) AS base
LEFT JOIN
(
SELECT [value]
FROM STRING_SPLIT(#SeverityIDsFilter, ';')
) AS DynamicSeverityFilter ON WorkorderSeverity = DynamicSeverityFilter.[value]
WHERE ((DynamicSeverityFilter.[value] IS NULL AND #SeverityIDsFilter = '') OR DynamicSeverityFilter.[value] IS NOT NULL)
ORDER BY base.WorkorderID, base.NextDate
OFFSET (#PageNumber * #ResultByPage) ROWS
FETCH NEXT #ResultByPage ROWS ONLY
RETURN
END

I think the "easiest" is to make this a two-step solution.
Fetch head data first into a table variable and use the offset thingy.
Join the head data with the row data and select "out" it together.
Simplified version of your function (but i also think you should convert it to regular procedure)
CREATE FUNCTION [dbo].[FctGetWorkorderAgenda]
(
#SeverityIDsFilter NVARCHAR(MAX) = '',
#Culture NVARCHAR(MAX) = 'FR-fr',
#StartDate DATETIMEOFFSET(7),
#EndDate DATETIMEOFFSET(7),
#PageNumber INT = 0,
#ResultByPage INT = 50
)
RETURNS #resTable TABLE
(
[WorkorderID] INT NOT NULL,
...
)
AS
BEGIN
-- Get data by filter
declare #head TABLE (workorderID INT)
insert into #head (workOrderID)
select wo.workorderID
from Workorder wo
... needed joins
where <your filters>
ORDER BY ...
OFFSET (#PageNumber * #ResultByPage) ROWS
FETCH NEXT #ResultByPage ROWS ONLY
-- Return joined data to the client
insert into #resTableBooking (
WO.WorkorderID,
...
)
SELECT WorkorderID
, ...
FROM #head h
inner join rest...
...
ORDER BY ...
RETURN
END

Related

Select unique rows from a select query result

I have procedure in which I am getting data from 4 tables by joining them.
Here is my code
alter PROCEDURE [dbo].[GetServiceRequestforLead]
#professionalArea nvarchar (35) = '',
#status nvarchar (15) = '',
#experience nvarchar (15) = '',
#PageNumber BIGINT = 1,
#PageSize BIGINT =20,
#userid bigint = 0
AS
BEGIN
SELECT *
FROM (
SELECT Row_number() OVER (ORDER BY sc.Addeddate DESC) AS Row, sc.*
, TotalRows = Count(*) OVER()
FROM (
select Mod_UserDetails.Email as LeadEmailId, Mod_UserDetails.ID as LeaduserId
, ProfessionType, Mod_UserDetails.FirstName as LeadFirstName, Mod_UserDetails.LastName as LeadLastName
, Mod_UserDetails.PhoneNo1 as LeadMobile
, f.*
from Lead_RequestForm f
inner join Lead_ProfessionalArea on Lead_ProfessionalArea.ID = f.Profession
left join ServiceProviderRequestMapping on f.RequestId = ServiceProviderRequestMapping.RequestId
left join mod_userdetails on mod_userdetails.ID = ServiceProviderRequestMapping.Leaduserid
where f.ExperienceRequired like '%'+#experience+'%'
AND f.Status like '%' + #status + '%'
AND Lead_ProfessionalArea.ProfessionType like '%'+ #professionalArea +'%'
AND (ServiceProviderRequestMapping.IsDeleted is null OR ServiceProviderRequestMapping.IsDeleted = 0)
) sc
) AS query
WHERE row > ( #PageSize *( #PageNumber -1))
AND row <= ( #PageSize * #PageNumber )
END
By executing this I am getting more than one row for RequestId column of Lead_RequestForm f table. Data is unique in both the rows but reuqest id is the same. I want to get only the first record with the same Requestid column.
i have added snap here request id column has duplicate value i want only one roq with a request id so want to select first one only
You can do as below -
alter PROCEDURE [dbo].[GetServiceRequestforLead]
#professionalArea nvarchar (35) = '',
#status nvarchar (15) = '',
#experience nvarchar (15) = '',
#PageNumber BIGINT = 1,
#PageSize BIGINT =20,
#userid bigint = 0
AS
BEGIN
Select Tb.*
from
(SELECT t.*, row_number() OVER (partition by RequestId order by Rowid) as seq_nbr
FROM (
SELECT Row_number() OVER (ORDER BY sc.Addeddate DESC) AS Row, sc.*
, TotalRows = Count(*) OVER()
FROM (
select Mod_UserDetails.Email as LeadEmailId, Mod_UserDetails.ID as LeaduserId
, ProfessionType, Mod_UserDetails.FirstName as LeadFirstName, Mod_UserDetails.LastName as LeadLastName
, Mod_UserDetails.PhoneNo1 as LeadMobile
, f.*
from Lead_RequestForm f
inner join Lead_ProfessionalArea on Lead_ProfessionalArea.ID = f.Profession
left join ServiceProviderRequestMapping on f.RequestId = ServiceProviderRequestMapping.RequestId
left join mod_userdetails on mod_userdetails.ID = ServiceProviderRequestMapping.Leaduserid
where f.ExperienceRequired like '%'+#experience+'%'
AND f.Status like '%' + #status + '%'
AND Lead_ProfessionalArea.ProfessionType like '%'+ #professionalArea +'%'
AND (ServiceProviderRequestMapping.IsDeleted is null OR ServiceProviderRequestMapping.IsDeleted = 0)
) sc
) AS query
WHERE row > ( #PageSize *( #PageNumber -1))
AND row <= ( #PageSize * #PageNumber )
)t
)Tb
where Tb.seq_nbr = 1
END

Iterate through derived value from temp table so it value can be used it a where condition using for loop

I can get the total for each of the items from a derived table like so:
declare #laneNum int
declare #startDate date = '2019-02-07'
declare #class int = 1
declare #id int
if OBJECT_ID('tempdb..#tempLaneNumber') IS NOT NULL
drop table [#tempLaneNumber]
create table #tempLaneNumber
(
LANE_NUMBER INT NULL
)
INSERT INTO #tempLaneNumber (LANE_NUMBER)
SELECT DISTINCT EXIT_LANE
FROM [dbo].[TOLL]
ORDER BY EXIT_LANE DESC
select l.LANE_NUMBER, COUNT(*)
from [dbo].[TOLL] t
inner join #tempLaneNumber l on t.EXIT_LANE = l.LANE_NUMBER
where convert(date, TRXN_DTIME) = #startDate
GROUP BY l.LANE_NUMBER
But what I need now is to iterate through each of the derived values so I can use it in a statement where each result can be placed in a variable. This is what I get in my current code...
I need to put LANE_NUMBER 4 into x4 variable and LANE_NUMBER 6 into x6 variable and so forth. How do I get to it?
EDIT
declare #laneNum int
declare #startDate date = '2019-02-07'
declare #class int = 1
declare #id int
if OBJECT_ID('tempdb..#tempLaneNumber') IS NOT NULL
drop table [#tempLaneNumber]
create table #tempLaneNumber
(
LANE_NUMBER INT NULL
)
INSERT INTO #tempLaneNumber (LANE_NUMBER)
SELECT DISTINCT EXIT_LANE
FROM [dbo].[TOLL]
ORDER BY EXIT_LANE DESC
;WITH CTE AS
(
select l.LANE_NUMBER, COUNT(*) CT
from [dbo].[TOLL] t
inner join #tempLaneNumber l on t.EXIT_LANE = l.LANE_NUMBER
where convert(date, TRXN_DTIME) = #startDate
GROUP BY l.LANE_NUMBER
)
SELECT * FROM CTE where LANE_NUMBER = 4
This is about right but the problem is I would need to hardcode the value "4" or "6" or "7". This sample has 4 results so it's okay. but what if I have 10 or more?
If you want to use the result later on you can use temp table like following.
create table #Results
(
LANE_NUMBER INT NULL,
[Count_LN] INT
)
INSERT INTO #Results
select l.LANE_NUMBER, COUNT(*) CT
from [dbo].[TOLL] t
inner join #tempLaneNumber l on t.EXIT_LANE = l.LANE_NUMBER
where convert(date, TRXN_DTIME) = #startDate
GROUP BY l.LANE_NUMBER
If you want to use the output immediately in the next statement, you can go for CTE like following.
;WITH CTE AS
(
select l.LANE_NUMBER, COUNT(*) CT
from [dbo].[TOLL] t
inner join #tempLaneNumber l on t.EXIT_LANE = l.LANE_NUMBER
where convert(date, TRXN_DTIME) = #startDate
GROUP BY l.LANE_NUMBER
)
SELECT * FROM CTE --USER YOUR CTE HERE
EDIT:
I am not able to understand your requirement fully, by any reason if you want to iterate the table and store every row's column value into a variable, you can try like following.
create table #Results
(
LANE_NUMBER INT NULL,
[Count_LN] INT
)
INSERT INTO #Results
select l.LANE_NUMBER, COUNT(*) CT
from [dbo].[TOLL] t
inner join #tempLaneNumber l on t.EXIT_LANE = l.LANE_NUMBER
where convert(date, TRXN_DTIME) = #startDate
GROUP BY l.LANE_NUMBER
declare #ln int
declare #ct int
While (Select Count(*) From #Results) > 0
Begin
select top 1 #ln = LANE_NUMBER, #ct = [Count_LN] from #Results
-- Use the variable #ln and #ct. For example, if you want to call a sp
-- exec call_someothersp #ln,#ct
Delete From #Results Where LANE_NUMBER = #ln and [Count_LN]=#ct
End

Understanding a SQL Statement

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

How to calculate no. of days between two datetime column in SQL Server

There are two tables, T1 includes start date column and T2 includes end date column. Both the columns have both date and time.
T1 has all the rows unique while T2 can have multiple rows for same id and in all the row the end date column might be different (each row with different date and time).
I want to calculate the difference (no. of days) between End date and the start date while keeping in mind that we have to only pick the last date which is lying in the End date column.
;WITH MaxEndDate AS
(
SELECT
T2.PrimaryKey,
MaxEndDate = MAX(EndDate)
FROM
T2
GROUP BY
T2.PrimaryKey
)
SELECT
T1.PrimaryKey,
T1.StartDate,
M.MaxEndDate,
AmountDays = DATEDIFF(DAY, T1.StartDate, M.MaxEndDate)
FROM
T1
INNER JOIN MaxEndDate AS M ON T1.PrimaryKey = M.PrimaryKey
I would recommend creating a temporary table using T2 something like
Select Distinct ID
,MAX(ENDDATE) As [ENDDATE]
INTO #TMPTABLE1
then you include this into T1
Select A.ID
,Startdate
,B.ENDDATE
,Datediff(day,A.STARTDATE,B.ENDDATE) as DAYS
From T1 as A inner join
#TEMPTABLE1 as B on A.ID = B.ID
--------get no of days among multiple dates----------
DECLARE #i INT , #numrows INT , #days INT , #Fdate DATETIME , #Tdate DATETIME;
SET
#days = 0;
DECLARE #employee_table TABLE ( idx SMALLINT PRIMARY KEY IDENTITY(1,
1) ,
EmpId INT ,
SinceDate DATETIME ,
TillDate DATETIME );
-- populate employee table INSERT #employee_table
SELECT
EmpId ,
SinceDate ,
TillDate
FROM
T_EmpPosting_PIS
WHERE
EmpId = 18
AND OfficeTypeID = 1
ORDER BY
TransDate;
--SELECT
*
FROM
#employee_table -- enumerate the table
SET
#i = 1;
SET
#numrows = ( SELECT
COUNT(*)
FROM
#employee_table );
IF #numrows > 0 WHILE ( #i <= ( SELECT
MAX(idx)
FROM
#employee_table ) ) BEGIN
SET
#Fdate = ( SELECT
SinceDate
FROM
#employee_table
WHERE
idx = #i );
IF ( #i = #numrows ) BEGIN
SET
#Tdate = GETDATE();
END;
ELSE BEGIN
SET
#Tdate = ( SELECT
TillDate
FROM
#employee_table
WHERE
idx = #i );
END;
SET
#days = ( SELECT
DATEDIFF(DAY,
#Fdate,
#Tdate) ) #days;
SET
#i = #i 1;
END;
SELECT
#days;

SQL Right Join?

Arrrgh, I am not getting this.
I have a table of accounts from Dynamics GP that has 7 columns. I need to fill in the blank months for accounts that didn't have any activity for a given month.
I have created an in memory table #MONTHS that has lines like so:
Account, Description, Year, Month, Month Name, Netchange, PeriodBal
1110000, NULL, 2006, 1, NULL, 0, NULL
This should match up with the same information coming from Dynamics GP. A similar line from GP would look like this:
1110000, Petty Cash, 2006, 1, January, 15.00, 343.97
If we did not spend any petty cash in February, then there would be no line for that account in 2/2006, I want to make the #MONTHS table RIGHT JOIN with the DynamicsGP table so that empty months are filled in.
Here's the abbreviated SQL shortened for readability:
SELECT Z.GPACCOUNTNO,
Z.DESCRIPTION,
Z.FISCALYEAR,
Z.FISCALPERIOD,
Z.FISCALPERIODNAME,
Z.NETCHANGE,
Z.PERIODBALANCE
FROM Z
RIGHT JOIN #MONTHS M
ON Z.GPACCOUNTNO = M.GPACCOUNTNO
AND Z.FISCALPERIOD = M.FISCALPERIOD
AND Z.FISCALYEAR = M.FISCALYEAR
The SQL just runs forever. (i.e. 5 minutes before I lose my patience)
I have verified that my #MONTHS table looks like I intend. I have tried doing a "UNION ALL" with the two tables and it gives me duplicates.
If Table Z does not have a current line for a given account/year/month, I want my #MONTHS table to add that line with a Netchange balance of 0.
Thank you for your help. The full SQL is below.
/* Create in memory table to hold account numbers */
DECLARE #i int
DECLARE #c int
DECLARE #ACCT char(129)
DECLARE #numrows int
DECLARE #numyears int
DECLARE #y int
DECLARE #m int
DECLARE #ACCT_TABLE TABLE (
idx smallint Primary Key IDENTITY(1,1),
account char(129)
)
/* Populate account number table */
INSERT #ACCT_TABLE
select distinct ACTNUMST from SBM01.[dbo].[GL00105]
/* Year table reads available years in the DB */
DECLARE #YEAR_TABLE TABLE (
idx smallint Primary Key IDENTITY(1,1),
YEAR1 smallint
)
/* Populate year table */
INSERT #YEAR_TABLE
SELECT distinct YEAR1 FROM SBM01.dbo.SY40101 ORDER BY YEAR1
/* Create our table of months to UNION to the main accounts */
DECLARE #MONTHS table (
GPACCOUNTNO char(129),
DESCRIPTION char(51),
FISCALYEAR smallint ,
FISCALPERIOD smallint,
FISCALPERIODNAME char(21),
NETCHANGE numeric(19, 5),
PERIODBALANCE numeric(19, 5)
)
/* Here comes the heavy lifting.
We loop over the account numbers and add year and month values.
*/
SET #i = 1
SET #numrows = (SELECT COUNT(*) FROM #ACCT_TABLE)
IF #numrows > 0
WHILE(#i <= (SELECT MAX(idx) FROM #ACCT_TABLE))
BEGIN
/* Get the next account number */
SET #ACCT = (SELECT account FROM #ACCT_TABLE WHERE idx = #i)
SET #c = 1
SET #numyears = (SELECT COUNT(*) FROM #YEAR_TABLE)
WHILE(#c <= (SELECT MAX(idx) FROM #YEAR_TABLE))
BEGIN
SET #y = (SELECT YEAR1 FROM #YEAR_TABLE WHERE idx = #c)
SET #m = '0'
WHILE(#m < '13')
BEGIN
INSERT INTO #MONTHS (GPACCOUNTNO, DESCRIPTION, FISCALPERIOD, FISCALYEAR, FISCALPERIODNAME, NETCHANGE, PERIODBALANCE)
VALUES (#ACCT, NULL, #m, #y, NULL, '0', NULL)
SET #m = #m + 1
END
SET #c = #c + 1
END
SET #i = #i + 1
END
/* We should now have a populated Database */
SELECT Z.GPACCOUNTNO, Z.DESCRIPTION, Z.FISCALYEAR, Z.FISCALPERIOD, Z.FISCALPERIODNAME, Z.NETCHANGE, Z.PERIODBALANCE
FROM ( SELECT RTRIM(B.[ACTNUMST]) AS GPACCOUNTNO,
RTRIM(C.[ACTDESCR]) AS DESCRIPTION,
A.[YEAR1] AS FISCALYEAR,
A.[PERIODID] AS FISCALPERIOD,
E.[PERNAME] AS FISCALPERIODNAME,
ISNULL(A.[PERDBLNC], 0) AS NETCHANGE,
( SELECT ISNULL(SUM(D.[PERDBLNC]), 0)
FROM SBM01.[dbo].[GL10110] D
WHERE D.[ACTINDX] = A.[ACTINDX]
AND D.[YEAR1] = A.[YEAR1]
AND D.[PERIODID] <= A.[PERIODID]
) AS PERIODBALANCE
FROM SBM01.[dbo].[GL10110] A
INNER JOIN SBM01.[dbo].[GL00105] B ON B.[ACTINDX] = A.[ACTINDX]
INNER JOIN SBM01.[dbo].[GL00100] C ON C.[ACTINDX] = A.[ACTINDX]
INNER JOIN SBM01.[dbo].[SY40100] E ON E.[YEAR1] = A.[YEAR1]
AND E.[PERIODID] = A.[PERIODID]
AND E.[SERIES] = 0
UNION ALL
SELECT RTRIM(B.[ACTNUMST]) AS GPACCOUNTNO,
RTRIM(C.[ACTDESCR]) AS DESCRIPTION,
A.[YEAR1] AS FISCALYEAR,
A.[PERIODID] AS FISCALPERIOD,
E.[PERNAME] AS FISCALPERIODNAME,
ISNULL(A.[PERDBLNC], 0) AS NETCHANGE,
( SELECT ISNULL(SUM(D.[PERDBLNC]), 0)
FROM SBM01.[dbo].[GL10111] D
WHERE D.[ACTINDX] = A.[ACTINDX]
AND D.[YEAR1] = A.[YEAR1]
AND D.[PERIODID] <= A.[PERIODID]
) AS PERIODBALANCE
FROM SBM01.[dbo].[GL10111] A
INNER JOIN SBM01.[dbo].[GL00105] B ON B.[ACTINDX] = A.[ACTINDX]
INNER JOIN SBM01.[dbo].[GL00100] C ON C.[ACTINDX] = A.[ACTINDX]
INNER JOIN SBM01.[dbo].[SY40100] E ON E.[YEAR1] = A.[YEAR1]
AND E.[PERIODID] = A.[PERIODID]
AND E.[SERIES] = 0
) Z
RIGHT JOIN #MONTHS M
ON Z.GPACCOUNTNO = M.GPACCOUNTNO
AND Z.FISCALPERIOD = M.FISCALPERIOD
AND Z.FISCALYEAR = M.FISCALYEAR
ORDER BY Z.[GPACCOUNTNO],
M.[FISCALYEAR],
M.[FISCALPERIOD]
Why don't you use the #Months table as the starting point (since it already gives you all the months you need) and fill-in the values from Z if they are available?
SELECT
M.GPACCOUNTNO,
M.DESCRIPTION,
M.FISCALYEAR,
M.FISCALPERIOD,
M.FISCALPERIODNAME,
ISNULL(Z.NETCHANGE, 0) as NETCHANGE
ISNULL(Z.PERIODBALANCE, 0) as PERIODBALANCE
FROM #MONTHS M
LEFT JOIN Z
ON Z.GPACCOUNTNO = M.GPACCOUNTNO
AND Z.FISCALPERIOD = M.FISCALPERIOD
AND Z.FISCALYEAR = M.FISCALYEAR
You can use a SQL case statement to join when null
CREATE TABLE #TMP
(
id int,
[month] datetime
)
INSERT INTO #TMP(id,[month])values(1,GETDATE())
INSERT INTO #TMP(id,[month])values(2,null)
INSERT INTO #TMP(id,[month])values(3,GETDATE())
INSERT INTO #TMP(id,[month])values(4,GETDATE())
CREATE TABLE #TMP2
(
id int,
[month] datetime
)
INSERT INTO #TMP2(id,[month])values(1,GETDATE())
INSERT INTO #TMP2(id,[month])values(2,GETDATE())
INSERT INTO #TMP2(id,[month])values(3,GETDATE())
INSERT INTO #TMP2(id,[month])values(4,GETDATE())
select * from #TMP
select * from #TMP2
SELECT #TMP.[id], case when #TMP.[month] is null then #TMP2.[month] else #TMP.month end
from #tmp
inner join #tmp2 on #tmp.id= #tmp2.id
drop table #tmp,#tmp2