Finding Events During a Timeframe - sql-server
Trying to figure out a query that could work for multiple situations. In a nutshell the data can be in one of twosituations. Lets say I'm looking for the record_id for events happened during a given time frame: 6/26/2012 10:00AM and 6/27/2012 11:00AM The records can look like this in the database:
Record Event Time
1 Start 6/26/2012 10:05AM
1 End 6/26/2012 10:45AM
2 Start 6/26/2012 09:55AM
2 End 6/26/2012 11:05AM
Getting record 1 is easy, just using the between function, but I'm stumbling trying to figure out a query to return both records 1 and 2.
Suggestions?
You can simply widen the range, but this may bring back different records than you intend.
SELECT RECORD, EVENT, TIME
FROM SO_RecordEvent AS R
WHERE TIme BETWEEN '6/26/2012 9:55AM' AND '6/26/2012 11:06AM'
This will return all records for anything that has either a start or end time within the range, including the associated records falling outside of the range (In other words records that only have one time in the range - but began before or ended after - it will still show the start or end time outside of it) and allow you you shorten your range.
;WITH X AS
(
SELECT RECORD,EVENT,TIME FROM SO_RecordEvent
)
SELECT R.RECORD,R.EVENT,R.TIME
FROM SO_RecordEvent AS R
INNER JOIN X ON R.Record = X.Record
WHERE X.TIme BETWEEN '6/26/2012 10:05AM' AND '6/26/2012 11:05AM'
GROUP BY R.RECORD,R.EVENT,R.TIME
But I think you may really want something like this, which truly gives you everything that was started during that time, even if it started AND ended outside of the range, as is your record 2 example.
EDIT
Changed logic - instead of addressing situations decided to think about it this way - anything that started within start and end, anything that ended within start and end, and anything that started before and ended after. I think this covers anything that runs during this time (starts before ends within, starts and ends within, starts within and ends after, and starts before and ends after)
SELECT X.RECORD,X.TIME AS STARTTIME,Y.TIME AS ENDTIME
FROM SO_RecordEvent AS X
INNER JOIN SO_RecordEvent Y ON Y.Record = X.Record AND Y.EVENT = 'END'
WHERE X.EVENT = 'START'
AND
((X.TIME >= '6/26/2012 10:00AM' AND X.TIME <= '6/26/2012 11:00AM')
OR (Y.TIME >= '6/26/2012 10:00AM' AND Y.TIME <= '6/26/2012 11:00AM')
OR (X.TIME <= '6/26/2012 10:00AM' AND Y.TIME >= '6/26/2012 11:00AM'))
Variables to play with:
DECLARE #START datetime, #END datetime
SET #START = '6/26/2012 10:00AM'
SET #END = '6/26/2012 11:00AM'
SELECT X.RECORD,X.TIME AS STARTTIME,Y.TIME AS ENDTIME
FROM SO_RecordEvent AS X
INNER JOIN SO_RecordEvent Y ON Y.Record = X.Record AND Y.EVENT = 'END'
WHERE X.EVENT = 'START'
AND
((X.TIME >= #START AND X.TIME <= #END)
OR (Y.TIME >= #START AND Y.TIME <= #END)
OR (X.TIME <= #START AND Y.TIME >= #END))
I'd probably join the table to itself - something like this:
SELECT *
FROM
Table leftside
JOIN Table rightside
ON leftside.Record = rightside.Record
WHERE
leftside.Event = 'Start'
and rightside.Event = 'End'
and [whatever time you want] >= leftside.Time
and [whatever time you want] <= rightside.Time
EDIT: Example to demonstrate
create table thingy (
record int,
event varchar(10),
time datetime )
insert thingy (record,event,time) values (1,'Start','6/26/2012 10:05AM')
insert thingy (record,event,time) values (1,'End','6/26/2012 10:45AM ')
insert thingy (record,event,time) values (2,'Start','6/26/2012 09:55AM')
insert thingy (record,event,time) values (2,'End','6/26/2012 11:05AM')
DECLARE #mytime datetime
SET #mytime = '6/26/2012 9:58AM'
SELECT *
FROM
thingy leftside
JOIN thingy rightside
ON leftside.Record = rightside.Record
WHERE
leftside.Event = 'Start'
and rightside.Event = 'End'
and #mytime >= leftside.Time
and #mytime <= rightside.Time
SET #mytime = '6/26/2012 10:10AM'
SELECT *
FROM
thingy leftside
JOIN thingy rightside
ON leftside.Record = rightside.Record
WHERE
leftside.Event = 'Start'
and rightside.Event = 'End'
and #mytime >= leftside.Time
and #mytime <= rightside.Time
Seems to give what I would expect - 1 row for the first query, 2 for the second.
Get record #s of all events that fall within the given range:
SELECT Record
FROM atable
WHERE Time BETWEEN #StartTime AND #EndTime
Now just get all rows whose record #s match those in the above query's result set, i.e. like this:
SELECT *
FROM atable
WHERE Record IN (
SELECT Record
FROM atable
WHERE Time BETWEEN #StartTime AND #EndTime
)
The simplest way to do this would be using the following:
WITH recs AS (
SELECT Record, MIN(tme) AS startTime, MAX(tme) AS endTime
FROM records
GROUP BY Record
)
SELECT * FROM
records
WHERE startTime >= #eventsAfter
AND endTime <= #eventsBefore
(this is how I interpreted your question, at least)
Related
Pivot Time Between into a Matrix
How can I pivot a start, end, start break, and end break times into a matrix that looks like the below? Ideally, I'd like to accomplish this in SQL Server. Essentially, I'm trying to visualize a timesheet (start time, end time, start break, end break), and pivot across the day (broken down by 15-minute increments) as 1 or 0. Start Time End Time Break Start Break Start 0:00 0:15 0:30 0:45 1:00 1:15 1:30 1:45 2:00 2:15 0:15 2:00 0:45 1:15 0 1 1 0 0 1 1 1 0 0
Revised version that handles time sheet entries that don't start and end exactly on the 15min intervals. -- Create test timesheet data DROP TABLE IF EXISTS #Timesheets GO CREATE TABLE #Timesheets(ID INT, StartTime TIME, EndTime TIME, BreakStart TIME, Breakend TIME) INSERT INTO #Timesheets(ID, StartTime,EndTime,BreakStart,Breakend) VALUES (1,'00:15','02:00','00:45','01:15'), (2,'08:03','16:50','12:05','13:00'), (3,'09:00','10:15','09:35','09:55') -- Recursively create a set of time periods in 15mins intervals DECLARE #StartTime TIME = '00:00' DECLARE #EndTime TIME = DATEADD(mi,1425,#StartTime) ;WITH TimePeriods AS ( SELECT #StartTime AS StartTime,DATEADD(mi,15,#StartTime) AS EndTime, CONVERT(VARCHAR(5),#StartTime,108) AS TimePeriod UNION ALL SELECT DATEADD(mi,15,StartTime),DATEADD(mi,30,StartTime), CONVERT(VARCHAR(5),DATEADD(mi,15,StartTime),108) FROM TimePeriods WHERE StartTime < #EndTime ) --select STRING_AGG( 'ISNULL('+QUOTENAME(Timeperiod)+',0) AS '+QUOTENAME(Timeperiod) ,',') from TimePeriods -- Map shifts to the time periods ,Shifts AS ( SELECT tp.TimePeriod ,ts.* FROM TimePeriods tp JOIN #Timesheets ts ON ( -- Shifts ((ts.StartTime >= tp.StartTime AND ts.StartTime < tp.EndTime OR ts.EndTime > tp.StartTime AND ts.EndTime < tp.EndTime) OR (tp.StartTime > ts.StartTime AND tp.StartTime < ts.EndTime) OR (tp.EndTime > ts.StartTime AND tp.EndTime < ts.EndTime)) ) ) -- Map Breaks to the Time Periods ,Breaks AS ( SELECT tp.TimePeriod ,tb.* FROM TimePeriods tp JOIN #Timesheets tb ON ( -- Breaks ((tb.BreakStart >= tp.StartTime AND tb.BreakStart < tp.EndTime OR tb.BreakEnd > tp.StartTime AND tb.BreakEnd < tp.EndTime) OR (tp.StartTime > tb.BreakStart AND tp.StartTime < tb.BreakEnd) OR (tp.EndTime > tb.BreakStart AND tp.EndTime < tb.BreakEnd)) ) ) -- Join the Time Periods to both shifts and breaks, create an Active field which deducts breaks from shifts ,TimeSheetPerPeriod AS ( select s.* ,CASE WHEN ISNULL(s.id,0)-ISNULL(b.id,0)>0 THEN 1 ELSE 0 END AS IsActive FROM TimePeriods tp JOIN Shifts s ON tp.TimePeriod = s.TimePeriod LEFT JOIN Breaks b ON tp.TimePeriod = b.TimePeriod ) -- Pivot the data into the desired format SELECT id,StartTime,EndTime,BreakStart,Breakend ,ISNULL([00:00],0) AS [00:00],ISNULL([00:15],0) AS [00:15],ISNULL([00:30],0) AS [00:30],ISNULL([00:45],0) AS [00:45],ISNULL([01:00],0) AS [01:00],ISNULL([01:15],0) AS [01:15],ISNULL([01:30],0) AS [01:30],ISNULL([01:45],0) AS [01:45],ISNULL([02:00],0) AS [02:00],ISNULL([02:15],0) AS [02:15],ISNULL([02:30],0) AS [02:30],ISNULL([02:45],0) AS [02:45],ISNULL([03:00],0) AS [03:00],ISNULL([03:15],0) AS [03:15],ISNULL([03:30],0) AS [03:30],ISNULL([03:45],0) AS [03:45],ISNULL([04:00],0) AS [04:00],ISNULL([04:15],0) AS [04:15],ISNULL([04:30],0) AS [04:30],ISNULL([04:45],0) AS [04:45],ISNULL([05:00],0) AS [05:00],ISNULL([05:15],0) AS [05:15],ISNULL([05:30],0) AS [05:30],ISNULL([05:45],0) AS [05:45],ISNULL([06:00],0) AS [06:00],ISNULL([06:15],0) AS [06:15],ISNULL([06:30],0) AS [06:30],ISNULL([06:45],0) AS [06:45],ISNULL([07:00],0) AS [07:00],ISNULL([07:15],0) AS [07:15],ISNULL([07:30],0) AS [07:30],ISNULL([07:45],0) AS [07:45],ISNULL([08:00],0) AS [08:00],ISNULL([08:15],0) AS [08:15],ISNULL([08:30],0) AS [08:30],ISNULL([08:45],0) AS [08:45],ISNULL([09:00],0) AS [09:00],ISNULL([09:15],0) AS [09:15],ISNULL([09:30],0) AS [09:30],ISNULL([09:45],0) AS [09:45],ISNULL([10:00],0) AS [10:00],ISNULL([10:15],0) AS [10:15],ISNULL([10:30],0) AS [10:30],ISNULL([10:45],0) AS [10:45],ISNULL([11:00],0) AS [11:00],ISNULL([11:15],0) AS [11:15],ISNULL([11:30],0) AS [11:30],ISNULL([11:45],0) AS [11:45],ISNULL([12:00],0) AS [12:00],ISNULL([12:15],0) AS [12:15],ISNULL([12:30],0) AS [12:30],ISNULL([12:45],0) AS [12:45],ISNULL([13:00],0) AS [13:00],ISNULL([13:15],0) AS [13:15],ISNULL([13:30],0) AS [13:30],ISNULL([13:45],0) AS [13:45],ISNULL([14:00],0) AS [14:00],ISNULL([14:15],0) AS [14:15],ISNULL([14:30],0) AS [14:30],ISNULL([14:45],0) AS [14:45],ISNULL([15:00],0) AS [15:00],ISNULL([15:15],0) AS [15:15],ISNULL([15:30],0) AS [15:30],ISNULL([15:45],0) AS [15:45],ISNULL([16:00],0) AS [16:00],ISNULL([16:15],0) AS [16:15],ISNULL([16:30],0) AS [16:30],ISNULL([16:45],0) AS [16:45],ISNULL([17:00],0) AS [17:00],ISNULL([17:15],0) AS [17:15],ISNULL([17:30],0) AS [17:30],ISNULL([17:45],0) AS [17:45],ISNULL([18:00],0) AS [18:00],ISNULL([18:15],0) AS [18:15],ISNULL([18:30],0) AS [18:30],ISNULL([18:45],0) AS [18:45],ISNULL([19:00],0) AS [19:00],ISNULL([19:15],0) AS [19:15],ISNULL([19:30],0) AS [19:30],ISNULL([19:45],0) AS [19:45],ISNULL([20:00],0) AS [20:00],ISNULL([20:15],0) AS [20:15],ISNULL([20:30],0) AS [20:30],ISNULL([20:45],0) AS [20:45],ISNULL([21:00],0) AS [21:00],ISNULL([21:15],0) AS [21:15],ISNULL([21:30],0) AS [21:30],ISNULL([21:45],0) AS [21:45],ISNULL([22:00],0) AS [22:00],ISNULL([22:15],0) AS [22:15],ISNULL([22:30],0) AS [22:30],ISNULL([22:45],0) AS [22:45],ISNULL([23:00],0) AS [23:00],ISNULL([23:15],0) AS [23:15],ISNULL([23:30],0) AS [23:30],ISNULL([23:45],0) AS [23:45] FROM ( SELECT distinct * FROM TimeSheetPerPeriod ) AS SourceTable PIVOT ( MAX(IsActive) FOR TimePeriod IN ([00:00],[00:15],[00:30],[00:45],[01:00],[01:15],[01:30],[01:45],[02:00],[02:15],[02:30],[02:45],[03:00],[03:15],[03:30],[03:45],[04:00],[04:15],[04:30],[04:45],[05:00],[05:15],[05:30],[05:45],[06:00],[06:15],[06:30],[06:45],[07:00],[07:15],[07:30],[07:45],[08:00],[08:15],[08:30],[08:45],[09:00],[09:15],[09:30],[09:45],[10:00],[10:15],[10:30],[10:45],[11:00],[11:15],[11:30],[11:45],[12:00],[12:15],[12:30],[12:45],[13:00],[13:15],[13:30],[13:45],[14:00],[14:15],[14:30],[14:45],[15:00],[15:15],[15:30],[15:45],[16:00],[16:15],[16:30],[16:45],[17:00],[17:15],[17:30],[17:45],[18:00],[18:15],[18:30],[18:45],[19:00],[19:15],[19:30],[19:45],[20:00],[20:15],[20:30],[20:45],[21:00],[21:15],[21:30],[21:45],[22:00],[22:15],[22:30],[22:45],[23:00],[23:15],[23:30],[23:45]) ) AS PivotTable
Update Column using calculation in last year from another table
I am trying to update (using Inner joins for three tables) item stats STAT for table IM_ITEM by highlighting items that sold less than 12 as "D" (Discontinue). The 2nd table PS_TKT_HIST_LIN has the Quantity sold column QTY_SOLD for each item on each day and the date column BUS_DAT. I also need a third table IM_INV to filter the data, I need to say the last received date LST_RECV_DAT for these items is earlier than "2019-01-01" and last sales date LST_SAL_DAT is after "2019-01-01". I used the following code UPDATE M SET M.STAT = 'D' FROM dbo.IM_ITEM AS M INNER JOIN IM_INV AS N ON M.ITEM_NO = N.ITEM_NO INNER JOIN dbo.PS_TKT_HIST_LIN S` ON M.ITEM_NO = S.ITEM_NO WHERE CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, N.LST_RECV_DAT))) <= '2019-01-01' AND CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, N.LST_SAL_DAT))) >= '2019-01-01' AND M.STAT = 'A' AND SUM(case when DATEPART(YYYY, (BUS_DAT)) = DATEPART(YYYY, DATEADD(YYYY, -1, getdate())) AND DATEPART(yyyy, (BUS_DAT)) = DATEPART(yyyy, DATEADD(YYYY, -1, getdate())) then qty_sold else 0)<12 It comes with an error Any advise please
You should use HAVING clause instead of Sum in where. You can use CTE to achieve the value, then update accordingly. ;with cte as( select ITEM_NO, .. from .. group by ITEM_NO having .. < 12 ) update M set SET M.STAT = 'D' from dbo.IM_ITEM AS M inner join cte on M.ITEM_NO = cte.ITEM_NO
You can't use an aggregate function in where clause unless defined under subquery.
SQL - Finding Gaps in Coverage
I am running this problem on SQL server Here is my problem. have something like this Dataset A FK_ID StartDate EndDate Type 1 10/1/2018 11/30/2018 M 1 12/1/2018 2/28/2019 N 1 3/1/2019 10/31/2019 M I have a second data source I have no control over with data something like this: Dataset B FK_ID SpanStart SpanEnd Type 1 10/1/2018 10/15/2018 M 1 10/1/2018 10/25/2018 M 1 2/15/2019 4/30/2019 M 1 5/1/2019 10/31/2019 M What I am trying to accomplish is to check to make sure every date within each TYPE M record in Dataset A has at least 1 record in Dataset B. For example record 1 in Dataset A does NOT have coverage from 10/26/2018 through 11/30/2018. I really only care about when the coverage ends, in this case I want to return 10/26/2018 because it is the first date where the span has no coverage from Dataset B. I've written a function that does this but it is pretty slow because it is cycling through each date within each M record and counting the number of records in Dataset B. It exits the loop when it finds the first one but I would really like to make this more efficient. I am sure I am not thinking about this properly so any suggestions anyone can offer would be helpful. This is the section of code I'm currently running else if #SpanType = 'M' begin set #CurrDate = #SpanStart set #UncovDays = 0 while #CurrDate <= #SpanEnd Begin if (SELECT count(*) FROM eligiblecoverage ec join eligibilityplan ep on ec.plandescription = ep.planname WHERE ec.masterindividualid = #IndID and ec.planbegindate <= #CurrDate and ec.planenddate >= #CurrDate and ec.sourcecreateddate = #MaxDate and ep.medicaidcoverage = 1) = 0 begin SET #Result = concat('NON Starting ',format(#currdate, 'M/d/yyyy')) BREAK end set #CurrDate = #CurrDate + 1 end end I am not married to having a function it just could not find a way to do this in queries that wasn't very very slow. EDIT: Dataset B will never have any TYPEs except M so that is not a consideration EDIT 2: The code offered by DonPablo does de-overlap the data but only in cases where there is an overlap at all. It reduces dataset B to: FK_ID SpanStart SpanEnd Type 1 10/1/2018 10/25/2018 M instead of FK_ID SpanStart SpanEnd Type 1 10/1/2018 10/25/2018 M 1 2/15/2019 4/30/2019 M 1 5/1/2019 10/31/2019 M I am still futzing around with it but it's a start.
I would approach this by focusing on B. My assumption is that any absent record would follow span_end in the table. So here is the idea: Unpivot the dates in B (adding "1" to the end dates) Add a flag if they are present with type "M". Check to see if any not-present records are in the span for A. Check the first and last dates as well. So, this looks like: with bdates as ( select v.dte, (case when exists (select 1 from b b2 where v.dte between b2.spanstart and b2.spanend and b2.type = 'M' ) then 1 else 0 end) as in_b from b cross apply (values (spanstart), (dateadd(day, 1, spanend) ) v(dte) where b.type = 'M' -- all we care about group by v.dte -- no need for duplicates ) select a.*, (case when not exists (select 1 from b b2 where a.startdate between b2.spanstart and b2.spanend and b2.type = 'M' ) then 0 when not exists (select 1 from b b2 where a.enddate between b2.spanstart and b2.spanend and b2.type = 'M' ) when exists (select 1 from bdates bd where bd.dte between a.startdate and a.enddate and bd.in_b = 0 ) then 0 when exists (select 1 from b b2 where a.startdate between b2.spanstart and b2.spanend and b2.type = 'M' ) then 1 else 0 end) from a; What is this doing? Four validity checks: Is the starttime valid? Is the endtime valid? Are any intermediate dates invalid? Is there at least one valid record?
Start by framing the problem in smaller pieces, in a sequence of actions like I did in the comment. See George Polya "How To Solve It" 1945 Then Google is your friend -- look at==> sql de-overlap date ranges into one record (over a million results) UPDATED--I picked Merge overlapping dates in SQL Server and updated it for our table and column names. Also look at theory from 1983 Allen's Interval Algebra https://www.ics.uci.edu/~alspaugh/cls/shr/allen.html Or from 2014 https://stewashton.wordpress.com/2014/03/11/sql-for-date-ranges-gaps-and-overlaps/ This is a primer on how to setup test data for this problem. Finally determine what counts via Ranking the various pairs of A vs B -- bypass those totally Within, then work with earliest PartialOverlaps, lastly do the Precede/Follow items. --from Merge overlapping dates in SQL Server with SpanStarts as ( select distinct FK_ID, SpanStart from Coverage_B as t1 where not exists (select * from Coverage_B as t2 where t2.FK_ID = t1.FK_ID and t2.SpanStart < t1.SpanStart and t2.SpanEnd >= t1.SpanStart) ), SpanEnds as ( select distinct FK_ID, SpanEnd from Coverage_B as t1 where not exists (select * from Coverage_B as t2 where t2.FK_ID = t1.FK_ID and t2.SpanEnd > t1.SpanEnd and t2.SpanStart <= t1.SpanEnd) ), DeOverlapped_B as ( Select FK_ID, SpanStart, (select min(SpanEnd) from SpanEnds as e where e.FK_ID = s.FK_ID and SpanEnd >= SpanStart) as SpanEnd from SpanStarts as s ) Select * from DeOverlapped_B Now we have something to feed into the next steps, and we can use the above as a CTE ====================================== with SpanStarts as ( select distinct FK_ID, SpanStart from Coverage_B as t1 where not exists (select * from Coverage_B as t2 where t2.FK_ID = t1.FK_ID and t2.SpanStart < t1.SpanStart and t2.SpanEnd >= t1.SpanStart) ), SpanEnds as ( select distinct FK_ID, SpanEnd from Coverage_B as t1 where not exists (select * from Coverage_B as t2 where t2.FK_ID = t1.FK_ID and t2.SpanEnd > t1.SpanEnd and t2.SpanStart <= t1.SpanEnd) ), DeOverlapped_B as ( Select FK_ID, SpanStart, (select min(SpanEnd) from SpanEnds as e where e.FK_ID = s.FK_ID and SpanEnd >= SpanStart) as SpanEnd from SpanStarts as s ), -- find A row's coverage ACoverage as ( Select a.*, b.SpanEnd, b.SpanStart, Case When SpanStart <= StartDate And StartDate <= SpanEnd And SpanStart <= EndDate And EndDate <= SpanEnd Then '1within' -- starts, equals, during, finishes When EndDate < SpanStart Or SpanEnd < StartDate Then '3beforeAfter' -- preceeds, meets, preceeded, met Else '2overlap' -- one or two ends hang over spanStart/End End as relation From Coverage_A a Left Join DeOverlapped_B b On a.FK_ID = b.FK_ID Where a.Type = 'M' ) Select * ,Case When relation1 = '2' And StartDate < SpanStart Then StartDate When relation1 = '2' Then DateAdd(d, 1, SpanEnd) When relation1 = '3' Then StartDate End as UnCoveredBeginning From ( Select * ,SUBSTRING(relation,1,1) as relation1 ,ROW_NUMBER() Over (Partition by A_ID Order by relation, SpanStart) as Rownum from ACoverage ) aRNO Where Rownum = 1 And relation1 <> '1'
SQL SUM() on one field with other fields on other conditions (the most efficient way)
I have a stored procedure to retrieve total orders (in $$$) on particular date and at the same time need to find out how much was a cash transaction vs credit card transaction. There are also others transaction type (eg. paypal) but does not need to be returned (don't ask me why). I have two choices, writing all in 1 query or go through cursor. Here is my 1 query SELECT #TotalOrder = SUM([TotalValue]), #TotalCash = (SELECT SUM([TotalValue]) FROM [dbo].[tblOrder] dbChild WHERE (dbChild.[OrderId] = dbMain.[OrderId]) AND (dbChild.[PaymentType] = 0)), #TotalCard = (SELECT SUM([TotalValue]) FROM [dbo].[tblOrder] dbChild WHERE (dbChild.[OrderId] = dbMain.[OrderId]) AND (dbChild.[PaymentType] = 1)) FROM [dbo].[tblOrder] dbMain WHERE [PaymentDate] BETWEEN #StartDate AND #EndDate; Is the query above ok? Alternatively, I can use cursor which loop through each record and accumulate the #TotalOrder, #TotalCash, and #TotalCard. SELECT [TotalValue], [PaymentType] FROM [dbo].[tblOrder] dbMain WHERE [PaymentDate] BETWEEN #StartDate AND #EndDate; --then use cursor to loop through each of the record. What do you think? Which one is the most efficient way? If both is not efficient, do you have any other suggestions?
The first method will most likely be the fastest, however you can refactor to use a single query: SELECT #TotalOrder = SUM([TotalValue]), #TotalCash = SUM(CASE WHEN [PaymentType] = 0 THEN [TotalValue] ELSE 0 END) #TotalCard = SUM(CASE WHEN [PaymentType] = 1 THEN [TotalValue] ELSE 0 END) FROM [dbo].[tblOrder] dbMain WHERE [PaymentDate] BETWEEN #StartDate AND #EndDate;
Getting current semester in SQL SERVER
I'm having a trouble on this query it says Incorrect syntax near the keyword 'BETWEEN' but when I tried to individually execute the BETWEEN conditions without CASE WHEN it runs normally, Also in relation to the Title is their a proper way to get the semester in SQL SERVER? DECLARE #ActiveSemester INT SET #ActiveSemester = ISNULL((SELECT [value] FROM spms_tblProfileDefaults WHERE eid = 7078 and ps_id = 1), (SELECT [value] FROM spms_configs WHERE actions = 'semester_active') ) SELECT FORMAT((SUM((DATEDIFF(MINUTE, a.actual_start_time, a.actual_end_time) - isnull(datediff(minute, break_start, break_end), 0))/ 60.0)), '0.00') FROM spms_tblSubTask as a LEFT JOIN pmis.dbo.employee as b ON a.eid = b.eid LEFT JOIN pmis.dbo.time_reference as c ON c.code = ISNULL(b.TimeReference, 'TIME14') LEFT JOIN dbo.spms_vwOrganizationalChart as e ON a.eid = e.eid cross apply ( select break_start = case when c.break_from between a.actual_start_time and a.actual_end_time then c.break_from when a.actual_start_time between c.break_from and c.break_to then a.actual_start_time else NULL end, break_end = case when c.break_to between a.actual_start_time and a.actual_end_time then c.break_to when a.actual_end_time between c.break_from and c.break_to then a.actual_end_time end ) as d WHERE b.Shift = 0 and a.eid = 7078 and YEAR(a.start_date_time) = YEAR(GETDATE()) and a.action_code = 1 and (CASE WHEN #ActiveSemester = 1 THEN a.start_date_time BETWEEN CAST(CONCAT('01/01/',YEAR(GETDATE())) as date) AND CAST(CONCAT('06/30/',YEAR(GETDATE())) as date) ELSE a.start_date_time BETWEEN CAST(CONCAT('07/01/',YEAR(GETDATE())) as date) AND CAST(CONCAT('12/31/',YEAR(GETDATE())) as date) END)
It seems that the other answer was Deleted and here's what I did as the other points out about the proper use of CASE WHEN WHERE 'other condition' and a.start_date_time BETWEEN (CASE WHEN #ActiveSemester = '1' THEN CAST(CONCAT('01/01/',YEAR(GETDATE())) as date) ELSE CAST(CONCAT('07/01/',YEAR(GETDATE())) as date) END) AND (CASE WHEN #ActiveSemester = '1' THEN CAST(CONCAT('06/30/',YEAR(GETDATE())) as date) ELSE CAST(CONCAT('12/31/',YEAR(GETDATE())) as date) END) with this, I get the results I wanted. Thanks
Assuming #ActiveSemester can take on the values 0 or 1, I'd just write this as: WHERE b.Shift = 0 and a.eid = 7078 and YEAR(a.start_date_time) = YEAR(GETDATE()) and a.action_code = 1 and #ActiveSemester = ((MONTH(a.start_date_time)-1)/6) Now, it's worth noting that this expression cannot use an index on start_date_time to satisfy this final predicate. If that's an issue, and the query isn't performing well, then I'd either recommend persisted computed columns in this table to extract the year and month value from the start_date_time column, modify the above query to use those columns and add appropriate indexes, or to populate a calendar table which has such values (and semester) properly represented and join to that table above, to again simplify the expressions and allow indexes to be used. Note, also, that the column name worries me. If it does contain a time portion as well as a date, then note that the expressions in your original query would have excluded any values that occurred after midnight on 30th June and 31st December1. I presume that wasn't your intent and the query above doesn't suffer this same shortcoming. 1Because 2018-06-30T00:01:00 is strictly later than 2018-06-30T00:00:00 (which is what CAST(CONCAT('06/30/',YEAR(GETDATE())) as date) expands out to) and so isn't BETWEEN the start and end dates you gave.