How to return current and previous row in SQL? - 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.

Related

How to select max date over the year function

I am trying to select the max date over the year, but it is not working. Any ideas on what to do?
SELECT a.tkinit [TK ID],
YEAR(a.tkeffdate) [Rate Year],
max(a.tkeffdate) [Max Date],
tkrt03 [Standard Rate]
FROM stageElite.dbo.timerate a
join stageElite.dbo.timekeep b ON b.tkinit = a.tkinit
WHERE a.tkinit = '02672'
and tkeffdate BETWEEN '2014-01-01' and '12-31-2014'
GROUP BY a.tkinit,
tkrt03,
a.tkeffdate
Perhaps you only want it by year and not rolled up by calendar date. For SQL server you can try this.
SELECT
…
MaxDate = MAX(a.tkeffdate) OVER (PARTITION BY a.tkinit, YEAR(a.tkeffdate)))
…
Or you could modify the query above to group by the year instead of date-->
GROUP BY a.tkinit,
tkrt03,
YEAR(a.tkeffdate)
You seem to want only one row and all the columns. Use ORDER BY and TOP:
SELECT TOP (1) tr.tkinit as [TK ID],
YEAR(tr.tkeffdate) as [Rate Year],
a.tkeffdate as [Max Date],
tkrt03 as [Standard Rate]
FROM stageElite.dbo.timerate tr JOIN
stageElite.dbo.timekeep tk
ON tk.tkinit = tr.tkinit
WHERE tr.tkinit = '02672' AND
tr.tkeffdate >= '2014-01-01' AND
tr.tkeffdate < '2015-01-01'
ORDER tr.tkeffdate DESC;
Note that I also fixed your date comparisons and table aliases.

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'

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
;

How to group some records by name and pivot some values

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

aggregate function warning by group clause

So ive been running to this problem constantly and maybe someone can give me a good explanation in how or why it wouldn't work. I'm trying to GROUP BY just one column CSHFutureTAs.Time and ive tried integrating the simple line
GROUP BY CSHFutureTAs.Time
however this gives me an error "You tried to execute a query that does not include the specified expression 'TA' as part of an aggregate function", can anyone help me ??
Complete SQL (without the GROUP CLAUSE):
SELECT CSHFutureTAs.TA
, CSHFutureTAs.TIME AS CSHGeneralTAs_TIME
, CSHFutureTAs.[CUT OFF TIME]
, CSHFutureTAs.SUNDAY AS CSHGeneralTAs_SUNDAY
, CSHFutureTAs.MONDAY AS CSHGeneralTAs_MONDAY
, CSHFutureTAs.TUESDAY AS CSHGeneralTAs_TUESDAY
, CSHFutureTAs.WEDNESDAY AS CSHGeneralTAs_WEDNESDAY
, CSHFutureTAs.THURSDAY AS CSHGeneralTAs_THURSDAY
, CSHFutureTAs.FRIDAY AS CSHGeneralTAs_FRIDAY
, CSHFutureTAs.SATURDAY AS CSHGeneralTAs_SATURDAY
, FUT_Totals.TIME AS GeneralTotals_Time
, FUT_Totals.SUNDAY AS GeneralTotals_SUNDAY
, FUT_Totals.MONDAY AS GeneralTotals_MONDAY
, FUT_Totals.TUESDAY AS GeneralTotals_TUESDAY
, FUT_Totals.WEDNESDAY AS GeneralTotals_WEDNESDAY
, FUT_Totals.THURSDAY AS GeneralTotals_THURSDAY
, FUT_Totals.FRIDAY AS GeneralTotals_FRIDAY
, FUT_Totals.SATURDAY AS GeneralTotals_SATURDAY
, CSHFutureTAs.[EXCEPTION DAYS]
, CSHFutureTAs.[EXCEPTION VALUE]
, IIf([FUT_Totals] ! [Time] = "09:00 - 21:00"
OR [FUT_Totals] ! [Time] = "10:00 - 22:00", 9, 1) AS SortKey
FROM
(
CSHFutureTAs
INNER JOIN FUT_Totals ON (CSHFutureTAs.[HG ID] = FUT_Totals.HG_ID)
AND (CSHFutureTAs.TIME = FUT_Totals.TIME)
)
INNER JOIN Current_INFO ON (CSHFutureTAs.[HG ID] = Current_INFO.[HG ID])
AND (CSHFutureTAs.[HEADER ID] = Current_INFO.[HEADER ID])
AND (FUT_Totals.HG_ID = Current_INFO.[HG ID])
ORDER BY IIf([FUT_Totals] ! [Time] = "09:00 - 21:00"
OR [FUT_Totals] ! [Time] = "10:00 - 22:00", 9, 1);
where exactly is your GROUP BY CSHFutureTAs.Time clause?
you need to group by one column, and any other column that is not part of the group must have an aggregation function on it like SUM or AVG for example.
Also I dont think you need that parentesys on your FROM. Why did you add that?