How to group some records by name and pivot some values - sql

I am working on a SQL Query to group the results of a View by Id to have only one Row per Id
with a maximum of three pivoted results and keeping some columns static : TestCaseId, TestName, Test Case Num, Owner
Actually this is the Query i Created to get the Desired output but is now working as expected because the MAX is always retriving the max value so i am getting only one row but the pivoted values are repeated to the right.
SELECT DISTINCT TBL1.[TestName], TBL1.[Test Case Num], TBL1.[Owner], MAX(TBL1.[Browser]) as 'Column1', MAX(TBL1.[Run Date]) as 'Column2', MAX(TBL1.[Status]) as 'Column3', MAX(TBL1.[Duration]) as 'Column4', MAX(TBL1.[ErrorMsg]) as 'Column5', MAX(TBL2.[Browser]) as 'Column6', MAX(TBL2.[Run Date]) as 'Column7', MAX(TBL2.[Status]) as 'Column8', MAX(TBL2.[Duration]) as 'Column9', MAX(TBL2.[ErrorMsg]) as 'Column10', MAX(TBL3.[Browser]) as 'Column11' , MAX(TBL3.[Run Date]) as 'Column12', MAX(TBL3.[Status]) as 'Column13', MAX(TBL3.[Duration]) as 'Column14', MAX(TBL3.[ErrorMsg]) as 'Column15'
FROM (SELECT DISTINCT T1.[TestCaseId], T1.[TestName], T1.[Test Case Num], T1.[Owner], T1.[Browser], T1.[Run Date], T1.[Status], T1.[Duration], T1.[ErrorMsg]
FROM [TestRunner].[dbo].RunsRawResults T1) TBL1
cross apply (SELECT DISTINCT T2.[TestCaseId], T2.[Browser], T2.[Run Date], T2.[Status], T2.[Duration], T2.[ErrorMsg]
FROM [TestRunner].[dbo].RunsRawResults T2
WHERE T2.[TestCaseId] = TBL1.[TestCaseId] AND T2.[Run Date] TBL1.[Run Date]) TBL2
cross apply (SELECT DISTINCT T3.[TestCaseId], T3.[Browser], T3.[Run Date], T3.[Status], T3.[Duration], T3.[ErrorMsg]
FROM [TestRunner].[dbo].RunsRawResults T3
WHERE T3.[TestCaseId] = TBL2.[TestCaseId] AND T3.[Run Date] TBL2.[Run Date] AND T3.[Run Date] TBL1.[Run Date]) TBL3
GROUP BY TBL1.[TestCaseId], TBL1.[TestName], TBL1.[Test Case Num], TBL1.[Owner]
Input -
Raw Data (Comes from the RunRawResults View)
Desired and Pivoted Output

Using a common table expression (cte) and row_number() we can simplify the identification and order of multiple run dates. This also lets us skip using distinct and group by.
Switching to outer apply lets us include results where there are less than 3 runs per TestCaseId.
;with cte as (
select *
, rn = row_number() over (
partition by TestCaseId
order by [Run Date]
)
from TestRunner.dbo.RunsRawResults
)
select
tbl1.TestName
, tbl1.[Test Case Num]
, tbl1.Owner
, tbl1.Browser
, [Run Date]_tbl1 = tbl1.[Run Date]
, Status_tbl1 = tbl1.Status
, Duration_tbl1 = tbl1.Duration
, ErrorMsg_tbl1 = tbl1.ErrorMsg
, Browser_tbl2 = tbl2.Browser
, [Run Date]_tbl2 = tbl2.[Run Date]
, Status_tbl2 = tbl2.Status
, Duration_tbl2 = tbl2.Duration
, ErrorMsg_tbl2 = tbl2.ErrorMsg
, Browser_tbl3 = tbl3.Browser
, [Run Date]_tbl3 = tbl3.[Run Date]
, Status_tbl3 = tbl3.Status
, Duration_tbl3 = tbl3.Duration
, ErrorMsg_tbl3 = tbl3.ErrorMsg
from cte as tbl1
outer apply (
select
i.[Run Date]
, i.Status
, i.Duration
, i.ErrorMsg
from cte as i
where i.TestCaseId = tbl1.TestCaseId
and i.rn = 2
) as tbl2
outer apply (
select
i.[Run Date]
, i.Status
, i.Duration
, i.ErrorMsg
from cte as i
where i.TestCaseId = tbl1.TestCaseId
and i.rn = 3
) as tbl3
where tbl1.rn = 1

Related

How to run Row_Number() with filtering

I have a table with multiple rows for each 'Case Number'. I want to pick one row for each Case Number and join this back to another table maintaining a one-to-one relationship.
The conditions to pick this row are :
1) First of all filter out all rows for each Case Number that have Stage = Cancelled
2) If you find Stage = 'In Progress' or 'Paused', pick that row. (Only one of these two can be present for a Case Number)
3) If not (2), then pick Stage = 'Completed' but for the latest 'Stop Time'. (This is where I thought we might have to use ROW_NUMBER())
I've already created a query to push in row numbers and pick up one row based on the latest 'Stop time' but I'm not able to figure out how to add the above filters and if-else conditions in there.
SELECT [Case Number],
ROW_NUMBER ( )
OVER ( PARTITION BY [Case Number] order by [Stop time] desc ) idx
,[Stage]
,[Time left]
,[SLA definition]
,[Elapsed time]
,[Elapsed percentage]
,[Start time]
,[Stop time]
,[Has breached]
,[Breach time]
,[Updated]
,[Updated by]
,[Created]
,[Created by]
FROM ( select * from [SLA_Data] where Stage != 'Cancelled' )v1
It's a bit hard to tell from your question but something like this is my interpretation (I'm not able to access SQL, nor did you provide enough test data so cannot test it)
select * from
(
SELECT [Task],...,...,
ROW_NUMBER ( )
OVER ( PARTITION BY Task order by
case
when Stage in('In Progress' ,'Paused') then 1
when Stage='Completed' then 2 end,
[Stop time] desc ) idx
)
where idx=1
Below code should work assuming Case_Number is present in the below table or the present table must be joined with the Case_Number Table
create view [dbo].[SLA_View] as select * from (
SELECT * FROM
(
SELECT [Task]
,[Stage]
,[Time left]
,[SLA definition]
,[Elapsed time]
,[Elapsed percentage]
,[Start time]
,[Stop time]
,[Has breached]
,[Breach time]
,[Updated]
,[Updated by]
,[Created]
,[Created by]
FROM
(
/* GETS SINGLE CASE FOR MULTIPLE STAGES */
SELECT *,ROW_NUMBER ( ) OVER ( PARTITION BY Task order by [Stage] desc) RNK
FROM [SLA_Data] WHERE [CASE_NUMBER] IN
(
/* GETS DISTINCT CASE NUMBER WITH STAGE = 'PAUSED' OR 'IN PROGRESS' */
SELECT DISTINCT [CASE_NUMBER]
FROM [SLA_Data]
WHERE [Stage] != 'Cancelled'
AND [Stage] IN ('Paused','In Progess')
GROUP BY [CASE_NUMBER]
HAVING COUNT(*) >= 1
)
)Y
WHERE RNK = 1
)Z
UNION
SELECT [Task]
,[Stage]
,[Time left]
,[SLA definition]
,[Elapsed time]
,[Elapsed percentage]
,[Start time]
,[Stop time]
,[Has breached]
,[Breach time]
,[Updated]
,[Updated by]
,[Created]
,[Created by]
FROM
(
SELECT *, ROW_NUMBER ( ) OVER ( PARTITION BY Task order by [start time] desc) idx
FROM [SLA_Data]
WHERE [CASE_NUMBER] NOT IN (
SELECT DISTINCT [CASE_NUMBER]
FROM [SLA_Data]
WHERE [Stage] != 'Cancelled'
AND [Stage] IN ('Paused','In Progess')
GROUP BY [CASE_NUMBER]
HAVING COUNT(*) > 1
)
)v1 where idx = 1
)

SQL IF type logic help requested

I have a SQL problem that I have been stuck on for days. So this is the context. I work for a company where employees have timesheets. Each timesheet has an ID but it is not unique because it is possible for an employee to have 2 timesheets for the same ID. The difference is that normally when you submit the sheet your status is ‘Posted’. But, sometimes people screw up their entries and it has to get re-submitted with changes. Therefore, the status ‘Adjusted’.
The logic I need is the following
-Where timesheet ID’s only have one value (count=1) always use ‘Posted’ status. If there is only one value but it is not ‘Posted’ return an error string saying ‘Error’.
-where timesheet IDs have more than one value and BOTH ‘Posted’ and ‘Adjusted’ show up as status always default to ‘Adjusted’. BOTH posted and adjusted must be present in this.
I have tried case and subquery but no luck. I also have a column ‘timesheet post date’ and logic is earliest date is always posted and later date is ‘adjusted’, but in some cases the posting dates are identical.
so as you can see, I need to look at the duplicate count in one column, and then choose the value if that count is >1 from another column.
SELECT t1.[Resource NUID]
,t1.[Timesheet ID]
,t1.[Timesheet Start Date]
,t1.[Timesheet End Date]
,t1.[Timesheet Posted Date]
,t1.[Timesheet Status]
,t1.[RunSourceID]
,t1.[SpanStartDate]
,t1.[SpanEndDate]
FROM [TIME_DW].[dbo].[Timecard_Timesheets] as t1, [TIME_DW].[dbo]. [Timecard_Timesheets] as t2
where t1.[Timesheet ID]=t2.[Timesheet ID]
and t1.[Resource NUID]='e066308' and t1.[Timesheet Status]<>'Open' and t1.[Timesheet Status]<>'Submitted'
group by
t1.[Resource NUID]
,t1.[Timesheet ID]
,t1.[Timesheet Start Date]
,t1.[Timesheet End Date]
,t1.[Timesheet Posted Date]
,t1.[Timesheet Status]
,t1.[RunSourceID]
,t1.[SpanStartDate]
,t1.[SpanEndDate]
order by t1.[Timesheet Start Date] asc
this is an example of an actual record that has two statuses
thanks
I am expecting logic like this:
select timesheet_id,
(case when count(*) = 1 and min(status) = 'Posted' then min(status)
when count(*) = 1 then 'Error'
when min(status) = 'Adjusted' and max(status) = 'Posted' then 'Adjusted'
else NULL -- this case is not covered in the description
end) as new_status
from [TIME_DW].[dbo].[Timecard_Timesheets]
group by timesheet_id;
I don't understand what all the other columns are going in the code in the question.
This should get you going in the right direction:
First we count rows by TimeSheet Id (CN) and we assign a row_number (RN) ordered by "Adjusted" records first, then everything else (you might want to add an adjustment date as a 2nd order by to get the most recent one first).
Then we add an error status if the first and only row is not a Status of "Posted".
Finally we select out only the rows WHERE RN=1
DECLARE #TimeSheet TABLE (Id INT, Status VARCHAR(15))
INSERT INTO #TimeSheet (Id,Status)
VALUES
(1,'Posted'),
(2,'Posted'),
(2,'Adjusted'),
(3,'Adjusted')
;WITH X AS
(
SELECT COUNT(2) OVER(PARTITION BY Id) AS CN,
ROW_NUMBER() OVER(PARTITION BY Id ORDER BY CASE WHEN Status='Adjusted' THEN 0 ELSE 1 END) AS RN,
*
FROM #TimeSheet
), Y AS
(
SELECT CASE WHEN CN=1 AND RN=1 AND Status<>'Posted' THEN 'Error'
ELSE ''
END AS Error,
*
FROM X
)
SELECT *
FROM Y
WHERE RN=1
from your code, I think you were trying to do this :
SELECT
ts.[Resource NUID]
, ts.[Timesheet ID]
, ts.[Timesheet Start Date]
, ts.[Timesheet End Date]
, ts.[Timesheet Posted Date]
, ts.[Timesheet Status]
, ts.[RunSourceID]
, ts.[SpanStartDate]
, ts.[SpanEndDate]
FROM
[TIME_DW].[dbo].[Timecard_Timesheets] as ts
JOIN (
SELECT *
, CASE
WHEN TimeSheetCount > 1 AND [Timesheet Status] <> 'Posted' THEN 'Adjusted'
WHEN TimeSheetCount = 1 AND [Timesheet Status] <> 'Posted' THEN 'Error'
ELSE 'Posted'
END NewStatus
FROM (
SELECT *
, COUNT(*) OVER(PARTITION BY t1.[Timesheet ID]) TimeSheetCount
, ROW_NUMBER() OVER(ORDER BY t1.[Timesheet Start Date]) RN
FROM
[TIME_DW].[dbo].[Timecard_Timesheets] as t1
) D
) t2 ON ts.[Timesheet ID] = t2.[Timesheet ID]
WHERE
ts.[Resource NUID] = 'e066308'
AND ts.[Timesheet Status] <> 'Open'
AND ts.[Timesheet Status] <> 'Submitted'

How to return current and previous row in SQL?

How do I return the current row and the previous row in a SQL query that is organized by date on a join? I have to join the "Crew" table with its "Detail" table. When I execute the query using a subselect, I get the same data for each crew. I am not sure how to pass the current crew ID down to the subselect so that only the previous days work for the current crew is returned.
SELECT Spread_Crew.Description
, Sum(Abs(Daily_Progress.Station_Number_
Begin_Daily_Progress.Station_Number_End)) AS [Feet Total]
, Spread_Crew.Hourly_Employee_Count AS [Hourly]
, Spread_Crew.Salary_Employee_Count AS [Salary]
, (Spread_Crew.Hourly_Employee_Count +
Spread_Crew.Salary_Employee_Count)*10 AS [Weekly Hours]
, (Date() - Spread_Crew.Actual_Start_Date) AS [Crew Days to Date]
, Round(([Feet Total]/ [Crew Days to Date]),0) AS [FT/Day]
, (SELECT Sum(Abs(Daily_Progress.Station_Number_Begin
Daily_Progress.Station_Number_End))
FROM Spread_Crew INNER JOIN Daily_Progress ON Spread_Crew.ID =
Daily_Progress.Spread_Crew_Id
WHERE (((Daily_Progress.PROGRESS_DATE)=[Report Date]))
) AS [Previous Footage]
FROM Spread_Crew LEFT JOIN Daily_Progress ON Spread_Crew.ID =
Daily_Progress.Spread_Crew_Id
GROUP BY Spread_Crew.Description
, Spread_Crew.Hourly_Employee_Count
, Spread_Crew.Salary_Employee_Count
, Spread_Crew.Sort_Order
, Spread_Crew.Print_On_Daily_Report
, Spread_Crew.Actual_Start_Date
HAVING (((Spread_Crew.Print_On_Daily_Report)=True))
ORDER BY Spread_Crew.Sort_Order;
Your subquery probably wants to be a correlated subquery:
(SELECT Sum(Abs(dp.Station_Number_Begin - dp.Station_Number_End))
FROM Daily_Progress as dp
WHERE Spread_Crew.ID = dp.Spread_Crew_Id AND
dp.PROGRESS_DATE = [Report Date]
) AS [Previous Footage]
The expression Spread_Crew.ID refers to the column in the outer SELECT.

Access Query - Summing Month to Date

I currently have a crosstab query set up to return amounts by month in 2017. This displays month totals for each location individually. I want to sum year to date (month 1-7) and have it only return one value for the location. I am having trouble doing this for some reason.
TRANSFORM Sum(Location.Amt) AS SumOfAmt
SELECT
Location.Div
, Location.Store
, Location.Year
, Location.Month
FROM
[Location Name]
INNER JOIN Location
ON [Location Name].Line = Location.Line
WHERE
(
Location.Store <> 100
AND Location.Year = 2017
AND Location.Month < 8
AND Location.Line < 11
GROUP BY
Location.Div
, Location.Store
, Location.Year
, Location.Month
ORDER BY
Location.Div
, Location.Store
, [Location Name].LineDesc
PIVOT [Location Name].LineDesc
;
In your select and group by clauses you've listed Year and Month which means it will aggregate for each value in those columns. If you don't want that behavior, you should remove those columns from the query.
TRANSFORM Sum(Location.Amt) AS SumOfAmt
SELECT
Location.Div
, Location.Store
FROM
[Location Name]
INNER JOIN Location
ON [Location Name].Line = Location.Line
WHERE
(
Location.Store <> 100
AND Location.Year = 2017
AND Location.Month < 8
AND Location.Line < 11
GROUP BY
Location.Div
, Location.Store
ORDER BY
Location.Div
, Location.Store
, [Location Name].LineDesc
PIVOT [Location Name].LineDesc
;

recursive common table expression with a view

This is what Im trying to do:
Create view vDetailsCommunications as
WITH Tickets AS
(
SELECT CallLog.CallID
, CallLog.RecvdDate
, Detail.ReqEffDate
, Asgnmnt.DateAcknow
, Asgnmnt.DateResolv
, Asgnmnt.Assignee
, Asgnmnt.GroupName
, CallLog.CallType
, Detail.ActionReq
, Detail.action_type
, (SELECT [Days] FROM NonWorkingDays(Asgnmnt.DateAcknow, Asgnmnt.DateResolv) AS NonWorkingDays_1) AS [Working Days]
, DATEDIFF(day, Asgnmnt.DateAcknow, Asgnmnt.DateResolv) AS [Days]
, (ROW_NUMBER() OVER(PARTITION BY Asgnmnt.CallID ORDER BY Asgnmnt.DateAcknow)) AS [Row Number]
FROM CallLog
INNER JOIN Detail ON CallLog.CallID = Detail.CallID
INNER JOIN Asgnmnt ON CallLog.CallID = Asgnmnt.CallID
WHERE (CallLog.CallType = 'ID Request-PAF')
AND (Detail.ActionReq = 'Hiring Action')
AND (DATEDIFF (DAY, Asgnmnt.DateAcknow, Asgnmnt.DateResolv) BETWEEN 0 AND 99)
AND (Asgnmnt.GroupName IN ('ID Admin', 'Systems Admin'))
AND (Detail.action_type IN ('Applicant Hire', 'Re-Hire'))
)
SELECT *
FROM Tickets
WHERE [Row Number] = 1
you need to define a schema in this function: NonWorkingDays.
ex:
SELECT [Days] FROM dbo.NonWorkingDays(Asgnmnt.DateAcknow, Asgnmnt.DateResolv)