Incorrect syntax near ';' sql - sql

I have a query for my stored procedure I am working on displayed below. I have an incorrect syntax near ';" which is at the very end of my query. Still pretty new to T-sql and can't figure out why I am receiving this error. I have a feeling it has something to do with the sub queries I have but i'm not sure. How can I change this to allow execution?
Declare #startTime DateTime
Declare #endTime DateTime
SET #startTime = '2014-03-28 8:00:00';
SET #endTime = '2014-03-28 17:00:00';
SELECT sum(datepart(hour, HoursRan) * 3600 + datepart(minute, HoursRan) * 60 + datepart(second, HoursRan)) as TotalHoursRan, sum(datepart(hour, DownTime) * 3600 + datepart(minute, DownTime) * 60 + datepart(second, DownTime)) as TotalDownTime, (TotalDownTime / HoursRan) as PercentDown
from (select cast(#endTime - #startTime as time) AS HoursRan
from (select cast(max(DateAndTime) - min(DateAndTime) as time) as DownTime
from (select pt.*,
sum(case when datediff(second, prevdt, DateAndTime) <= 1 then 0 else 1 end) over
(order by DateAndTime) as grp
from (select pt.*, lag(DateAndTime) over (order by DateAndTime) as prevdt
from IncomingProductTracker pt
where Line4AFaultStatus = 1 and
DateAndTime > '2014-03-28 8:00:00' and
DateAndTime < '2014-03-28 17:00:00'
) pt
) pt
group by grp) pt;

As others have said, you can use a different alias to make finding errors like this easier. In this case, you were missing a name for one of your sub-queries.
DECLARE #startTime DATETIME
DECLARE #endTime DATETIME
SET #startTime = '2014-03-28 8:00:00';
SET #endTime = '2014-03-28 17:00:00';
SELECT SUM(DATEPART(hour, HoursRan) * 3600 + DATEPART(minute, HoursRan) * 60
+ DATEPART(second, HoursRan)) AS TotalHoursRan
, SUM(DATEPART(hour, DownTime) * 3600 + DATEPART(minute, DownTime) * 60
+ DATEPART(second, DownTime)) AS TotalDownTime
, ( TotalDownTime / HoursRan ) AS PercentDown
FROM ( SELECT CAST(#endTime - #startTime AS TIME) AS HoursRan
FROM ( SELECT CAST(MAX(DateAndTime) - MIN(DateAndTime) AS TIME) AS DownTime
FROM ( SELECT pt.*
, SUM(CASE WHEN DATEDIFF(second,
prevdt,
DateAndTime) <= 1
THEN 0
ELSE 1
END) OVER ( ORDER BY DateAndTime ) AS grp
FROM ( SELECT pt.*
, lag(DateAndTime) OVER ( ORDER BY DateAndTime ) AS prevdt
FROM IncomingProductTracker pt
WHERE Line4AFaultStatus = 1
AND DateAndTime > '2014-03-28 8:00:00'
AND DateAndTime < '2014-03-28 17:00:00'
) pt
) pt
GROUP BY grp
) pt
) pt;
Using different aliases:
DECLARE #startTime DATETIME
DECLARE #endTime DATETIME
SET #startTime = '2014-03-28 8:00:00';
SET #endTime = '2014-03-28 17:00:00';
SELECT SUM(DATEPART(hour, HoursRan) * 3600 + DATEPART(minute, HoursRan) * 60
+ DATEPART(second, HoursRan)) AS TotalHoursRan
, SUM(DATEPART(hour, DownTime) * 3600 + DATEPART(minute, DownTime) * 60
+ DATEPART(second, DownTime)) AS TotalDownTime
, ( TotalDownTime / HoursRan ) AS PercentDown
FROM ( SELECT CAST(MAX(DateAndTime) - MIN(DateAndTime) AS TIME) AS DownTime
, CAST(#endTime - #startTime AS TIME) AS HoursRan
FROM ( SELECT a.*
, SUM(CASE WHEN DATEDIFF(second, prevdt,
DateAndTime) <= 1
THEN 0
ELSE 1
END) OVER ( ORDER BY DateAndTime ) AS grp
FROM ( SELECT pt.*
, lag(DateAndTime) OVER ( ORDER BY DateAndTime ) AS prevdt
FROM IncomingProductTracker pt
WHERE Line4AFaultStatus = 1
AND DateAndTime > '2014-03-28 8:00:00'
AND DateAndTime < '2014-03-28 17:00:00'
) a
) b
GROUP BY grp
) c;

I believe declare statements should be ended with semi-colons.
http://technet.microsoft.com/en-us/library/ms188927.aspx

Related

How to break datetime in 15 minute interval in sql sever 2014

I have split the below query in 15 minute interval on the basis of Start datetime but this query is not providing the exact result set
as i am expecting.
Below is the example of query i want to execute.
select Date_Stamp,
Case when substring(convert(char(8),starttime,114), 1, 8) between '12:00:01 AM'and '12:15:00 AM' then '0015'
when substring(convert(char(8),starttime,114), 1, 8) between '12:15:01 AM'and '12:30:00 AM' then '0030'
when substring(convert(char(8),starttime,114), 1, 8) between '12:30:01 AM'and '12:45:00 AM' then '0045'
when substring(convert(char(8),starttime,114), 1, 8) between '12:45:01 AM'and '01:00:00 AM' then '0100'
and i want the result as
Date Need result set
12:01 AM '0015'
'12:15:01 '0030'
'12:30:01 '0045'
'12:45:01 '0100'
'01:00:01 '0115'
'01:15:01 '0130'
'01:30:01 '0145'
'01:45:01 '0200'
'02:00:01 '0215'
'02:15:01 '0230'
'02:30:01 '0245'
3:00:00 ' '0015'
'12:30:00 '0030'
'12:45:00 '0045'
'01:00:00 '0100'
'01:15:00 '0115'
'01:30:00 '0130'
'01:45:00 '0145'
'02:00:00 '0200'
'02:15:00 '0215'
'02:30:00 '0230'
'02:45:00 '0245'
Just change #starttime with your column name
DECLARE #starttime datetime = getdate()
SELECT CONCAT(CASE WHEN DATEPART(HH, #starttime) <= 9
THEN '00'+ CAST(DATEPART(HH, #starttime) AS VARCHAR(2))
ELSE '0'+CAST(DATEPART(HH, #STARTTIME) AS VARCHAR(2))
END,
CASE WHEN DATEPART(MINUTE, #STARTTIME) BETWEEN 1 AND 15
THEN 15
WHEN DATEPART(MINUTE, #STARTTIME) BETWEEN 16 AND 30
THEN 30
WHEN DATEPART(MINUTE, #STARTTIME) BETWEEN 31 AND 45
THEN 45
WHEN DATEPART(MINUTE, #STARTTIME) BETWEEN 46 AND 59 OR DATEPART(MINUTE, #STARTTIME) = 0
THEN 00
END)
You can use this date generator:
DEMO
DECLARE #Break INT = 15
;WITH Numbers (n) as
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1
FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0)) a(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d(n)
)
,Dates as
(
SELECT dt
FROM Numbers
CROSS APPLY
(
VALUES (DATEADD(MINUTE , n, CAST(CAST(GETDATE() AS DATE) AS DATETIME)))
) X(Dt)
WHERE N % #Break = 0
AND CAST(DT AS DATE) = CAST(GETDATE() AS DATE) --Only for today's date
)
SELECT CONVERT(VARCHAR(10),Dt,108) [Time] , REPLACE(CONVERT(VARCHAR(5),ISNULL(Lead(Dt) OVER (ORDER BY Dt) , DATEADD(MINUTE,#Break,Dt)),108), ':','') Grp
FROM Dates
It appears you're using datetime and have only taken the substring of the time. A string cannot be compared to a time, without being casted to the time datatype.
For example:
DECLARE #mytable TABLE (starttime datetime)
INSERT INTO #mytable VALUES ('2018-03-13 00:00:01'), ('2018-03-15 00:00:01')
SELECT * FROM #mytable
select CAST(starttime as time(0)) AS [thetime],
Case when CAST(starttime as time) between '12:00:01 AM'and '12:15:00 AM' then '0015'
when CAST(starttime as time) between '12:15:01 AM'and '12:30:00 AM' then '0030'
when CAST(starttime as time) between '12:30:01 AM'and '12:45:00 AM' then '0045'
when CAST(starttime as time) between '12:45:01 AM'and '01:00:00 AM' then '0100'
END AS [Interval]
FROM #mytable
Produces:
thetime Interval
00:00:01 0015
00:15:01 0030

Count how many times a time occurs within a date range

I could not think of a good way to phrase this question to search properly if its already been asked.
I'm looking for a way in SQL 2008 R2 to count how many times 6pm occurs between two datetime values.
For example between '2017-04-17 19:00:00' and '2017-04-19 17:00:00' 6pm only occurs once even though the times span 3 different days.
Between '2017-04-17 18:00:00' and '2017-04-19 18:00:00' it occurs 3 times whilst also spanning 3 days.
Heres a really silly made up expression of what I want for illustration.
timecount(hh, 6, min(datefield), max(datefield))
Thank you
A simple query to count:
DECLARE #StartDate datetime = '2017-04-17 18:00:00'
DECLARE #EndDate datetime = '2017-04-19 18:00:00'
SELECT
CASE
WHEN CAST(#StartDate AS time) <= '18:00' AND CAST(#EndDate AS time) >= '18:00'
THEN datediff(day, #StartDate, #EndDate) + 1
WHEN CAST(#StartDate AS time) <= '18:00' AND CAST(#EndDate AS time) < '18:00'
THEN datediff(day, #StartDate, #EndDate)
WHEN CAST(#StartDate AS time) > '18:00' AND CAST(#EndDate AS time) >= '18:00'
THEN datediff(day, #StartDate, #EndDate)
ELSE datediff(day, #StartDate, #EndDate) - 1
END AS TotalCount
This will give you each hour and the number of occurences:
select datepart(hh, DateColumn) as TheHours, count(*) as occurs
from MyTable
where DateColumn between #SomeDate and #SomeOtherDate
group by datepart(hh, DateColumn)
Or just for 6pm:
select count(*)
from MyTable
where datepart(hh, DateColumn) = 18
and DateColumn between #SomeDate and #SomeOtherDate
DECLARE
#Time time = '18:00',
#From datetime = '2017-04-17 18:00:00',
#To datetime = '2017-04-19 18:00:00'
SELECT
CASE
-- Same date
WHEN DATEDIFF(DAY, #From, #To) = 0 THEN
CASE WHEN CAST(CAST(#From AS date) AS datetime) + #Time BETWEEN #From AND #To THEN 1 ELSE 0 END
-- Not same date
WHEN #From <= #To THEN
CASE WHEN #Time >= CAST(#From AS time) THEN 1 ELSE 0 END
+ DATEDIFF(DAY, #From, #To) - 1
+ CASE WHEN #Time <= CAST(#To AS time) THEN 1 ELSE 0 END
-- Invalid range
ELSE 0
END AS CountOfTime
Try below formula I have tried with different scenario and it works, let me know if I miss any scenario and not work as per your requirement.
DECLARE #firstDate Datetime='17-Apr-2017 17:00:00'
DECLARE #secondDate Datetime='17-Apr-2017 18:59:00'
SELECT
CASE WHEN DATEDIFF(day,#firstDate,#secondDate)=0
THEN IIF(CAST(#firstDate AS TIME) <='18:00' AND DATEPART(hh,#secondDate) >=18,1,0)
ELSE
CASE WHEN
(
CAST(#firstDate AS TIME) <='18:00' AND CAST(#secondDate AS TIME) <'18:00'
OR
CAST(#firstDate AS TIME) >'18:00' AND CAST(#secondDate AS TIME) >='18:00'
)
THEN DATEDIFF(day,#firstDate,#secondDate)
WHEN CAST(#firstDate AS TIME) <='18:00' AND CAST(#secondDate AS TIME) >='18:00' THEN DATEDIFF(day,#firstDate,#secondDate)+1
ELSE DATEDIFF(day,#firstDate,#secondDate)-1
END
END AS TotalCount
Try the below script, using CTE
DECLARE #F_DATE AS DATETIME = '2017-04-17 19:00:00'
,#T_DATE AS DATETIME = '2017-04-19 17:00:00'
;WITH CTE
AS (
SELECT (CASE WHEN DATEPART(HH,#F_DATE) <= 18
THEN #F_DATE
ELSE (CASE WHEN DATEDIFF(DAY,#F_DATE,#T_DATE) > 0
THEN DATEADD(DAY,1,#F_DATE) END)
END) AS CDATE
UNION ALL
SELECT DATEADD(DAY,1,CDATE)
FROM CTE
WHERE DATEADD(DAY,1,CDATE) <= #T_DATE
)
SELECT COUNT(CDATE) DATE_COUNT
FROM CTE
OPTION ( MAXRECURSION 0 )
Here's the count of every 6pm between two datetime:
DECLARE #StartDate datetime
DECLARE #EndDate datetime
set #StartDate = '2017-04-17 19:00:00'
set #EndDate = '2017-04-19 17:00:00'
;WITH cte1 (S) AS (
SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (S)
),
cte2 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte1 AS cte2),
cte3 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte2 AS cte2)
select count(datepart(hour,result)) as count from
(SELECT TOP (DATEDIFF(hour, #StartDate, #EndDate) + 1)
result = DATEADD(hour, ROW_NUMBER() OVER(ORDER BY S) - 1, #StartDate)
FROM cte3) as res where datepart(hour,result) = 18
Here's the detailed view of 6pm between two datetime:
DECLARE #StartDate datetime
DECLARE #EndDate datetime
set #StartDate = '2017-04-17 19:00:00'
set #EndDate = '2017-04-19 17:00:00'
;WITH cte1 (S) AS (
SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (S)
),
cte2 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte1 AS cte2),
cte3 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte2 AS cte2)
select result,datepart(hour,result) from
(SELECT TOP (DATEDIFF(hour, #StartDate, #EndDate) + 1)
result = DATEADD(hour, ROW_NUMBER() OVER(ORDER BY S) - 1, #StartDate)
FROM cte3) as res where datepart(hour,result) = 18
Here gives the count between any date ranges
declare #time datetime='06:00:00'
declare #startDate datetime='04/20/2017 05:00:00'
declare #enddate datetime='04/21/2017 05:00:00'
SELECT
case
WHEN datediff(ss,#time, convert(time(0),#startDate)) <=0 and datediff(ss,#time, convert(time(0),#enddate)) >=0
THEN datediff(dd,#startDate,#enddate) +1
WHEN (datediff(ss,#time, convert(time(0),#startDate)) <=0 and
datediff(ss,#time, convert(time(0),#enddate)) <=0
OR
datediff(ss,#time, convert(time(0),#startDate))> 0 and
datediff(ss,#time, convert(time(0),#enddate)) >0
OR
datediff(ss,#time, convert(time(0),#startDate))> 0 and datediff(ss,#time, convert(time(0),#enddate)) <=0
)
then datediff(dd,#startDate,#enddate)
ELSE
datediff(dd,#startDate,#enddate)-1
END

Showing only hours and minutes?

How to display only hours and minutes in a field if I get them separately
[SELECT
D.numOperador,
SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) / 60 AS \[Horas\] ,
SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) % 60 AS \[Minutos\]
FROM
trkOperadores O
INNER JOIN trfDespacho D ON O.NumOperador = D.numOperador
WHERE
O.cveTipoOperador = 2
AND O.NumOperador = 900200
AND D.FechaSalida>='2017-03-10 00:00:00.000' AND D.FechaLlegada<='2017-03-11 00:00:00.000'
GROUP BY
D.NumOperador;
GO]
Time
If you just want to join hrs and mns together in the result, concatenate both of them :
SELECT
D.numOperador,
( cast ( SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) / 60 as varchar)
+
cast ( SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) % 60 AS varchar ) ) as time
FROM
trkOperadores O
INNER JOIN trfDespacho D ON O.NumOperador = D.numOperador
WHERE
O.cveTipoOperador = 2
AND O.NumOperador = 900200
AND D.FechaSalida>='2017-03-10 00:00:00.000' AND D.FechaLlegada<='2017-03-11 00:00:00.000'
GROUP BY
D.NumOperador;
GO]
I assume that you want something like this.
DECLARE #D1 DATETIME = '20170401'
DECLARE #D2 DATETIME = '20170402 00:05:00'
SELECT RIGHT( '00' + CAST(DATEDIFF(MINUTE, #D1, #D2) /60 AS VARCHAR(2)) , 2) + ':' + RIGHT( '00' + CAST(DATEDIFF(MINUTE, #D1, #D2) % 60 AS VARCHAR(2)) , 2)
-- 24:05
SELECT
D.numOperador,
SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) / 60 AS [Horas] ,
SUM(DATEDIFF(MINUTE, D.FechaSalida, D.FechaLlegada)) % 60 AS [Minutos]
CONVERT(VARCHAR(10),CAST(CAST (D.FechaSalida AS FLOAT) - CAST (D.FechaLlegada AS FLOAT) / 86400. AS DATETIME),108) --86400 equal 1 day
FROM
trkOperadores O INNER JOIN trfDespacho D
ON O.NumOperador = D.numOperador
WHERE
O.cveTipoOperador = 2
AND O.NumOperador = 900200
AND D.FechaSalida>='2017-03-10 00:00:00.000' AND D.FechaLlegada<='2017-03-11 00:00:00.000'
GROUP BY
D.NumOperador;
GO

How to display event hour by hour in SQL?

Create table tblEvent ( Event_ID int, Start_Time datetime, End_Time datetime )
insert into tblEvent values(1,'2015-02-10 9:00:00.000','2015-02-10 11:00:00.000')
insert into tblEvent values(2,'2015-02-10 11:00:00.000','2015-02-10 11:20:00.000')
insert into tblEvent values(3,'2015-02-10 11:20:00.000','2015-02-10 13:00:00.000')
and want to be display like below
Hour Event_ID [Start_End]
9 1 9:00-10:00
10 1 10:00-11:00
11 2 11:00-11:20
11 3 11:20-12:00
12 3 12:00-13:00
and we can make the End_Time of Event 3 become 13:30
we had to be display
13 3 13:00-13:30
Can anyone help me?
You can use DATEPART function
DATEPART(HOUR, [Start_End]) AS Hour
select blocks.Hour, e.Event_Id,
format(case when e.Start_Time > blocks.Start_Time then e.Start_Time else blocks.Start_Time end, 'HH:mm') +
'-' +
format(case when e.End_Time < blocks.End_Time then e.End_Time else blocks.End_Time end, 'HH:mm')
from
tblEvent as e inner join
(
select
d0.n + d1.n * 4 as Hour,
dateadd(hh, d0.n + d1.n * 4, cast(cast(current_timestamp as date) as datetime)) as Start_Time,
dateadd(hh, d0.n + d1.n * 4 + 1, cast(cast(current_timestamp as date) as datetime)) as End_Time
from
(select 0 as n union all select 1 union all select 2 union all select 3) as d0,
(select 0 as n union all select 1 union all select 2 union all select 3 union all select 4 union all select 5) as d1
) as blocks
on blocks.End_Time > e.Start_Time and blocks.Start_Time < e.End_Time
order by Event_Id, Hour
Here's a start. SQL Server? Is current day enough? You don't have the format() on SQL 2008 so you'll have to do that part yourself.
I'm not sure this handles all the cases exactly the way you want. You can take the basic idea and extend it across a longer range of hours, say 168 for a full week.
http://sqlfiddle.com/#!6/819c0/9
TRY Some thing like this.This sample data is running ok.
Please provide another sample data atleast 10 rows and don't forget to paste desired output.
Also read my comment in script.
DECLARE #tblEvent TABLE (
Event_ID INT
,Start_Time DATETIME
,End_Time DATETIME
)
INSERT INTO #tblEvent
VALUES (
1
,'2015-02-10 9:00:00.000'
,'2015-02-10 11:00:00.000'
)
,(
2
,'2015-02-10 11:00:00.000'
,'2015-02-10 11:20:00.000'
)
,(
3
,'2015-02-10 11:20:00.000'
,'2015-02-10 13:00:00.000'
);
--select *,DATEdiff(hour,a.Start_Time,a.End_Time) from #tblEvent a
;
WITH CTE
AS (
SELECT *
,ROW_NUMBER() OVER (
ORDER BY Start_Time
) RN
,DATEdiff(hour, Start_Time, End_Time) Diff
FROM #tblEvent
)
--select * from cte
,CTE1
AS (
SELECT Event_ID
,Start_Time
,CASE
WHEN Diff > 1
THEN DATEADD(minute, 60 - DATEPART(minute, Start_Time), Start_Time)
ELSE End_Time
END End_Time
,RN
,DIFF
,1 RN1
,DATEPART(minute, Start_Time) DIFFMIN
FROM CTE
--WHERE RN = 1
UNION ALL
SELECT CASE
WHEN A.Diff > B.DIFF
THEN b.Event_ID
ELSE a.Event_ID
END
,B.End_Time Start_Time
,CASE
WHEN A.Diff > B.DIFF
THEN DATEADD(minute, 60 - DATEPART(minute, B.Start_Time), B.End_Time)
ELSE A.End_Time
END End_Time
,CASE
WHEN A.Diff > B.DIFF
THEN B.RN
ELSE B.RN + 1
END RN
,CASE
WHEN A.Diff > B.DIFF
THEN B.DIFF - 1
ELSE A.Diff
END
,RN1 + 1
,0
FROM CTE1 B
CROSS APPLY (
SELECT *
FROM CTE
WHERE RN = B.RN
) A
WHERE B.DIFF > 0
)
SELECT [Hour]
,Event_ID
,[Start_End]
FROM (
SELECT DATEPART(HOUR, Start_Time) [Hour]
,ROW_NUMBER() OVER (
PARTITION BY Start_Time ORDER BY Start_Time
) RN2
,Event_ID
,CONVERT(VARCHAR(5), Start_Time, 114) + '-' + CONVERT(VARCHAR(5), End_Time, 114) [Start_End]
FROM CTE1
) TBL
WHERE RN2 = 1
--BELOW QUERY RETURN 6 ROWS
-- I AM TRYING TO ELIMINATE THE EXTRA ROWS WITHOUT ROW_NUMBER
--WHICH WOULD BE MORE OPTIMIZE,BUT I AM NOT GETTING WHAT ACTUALLY CAUSING THIS BEHAVIOUR
--MEANWHILE YOU CAN TEST OTHER SAMPLE DATA,AND THROW OTHER SAMPLE DATA
--SELECT DATEPART(HOUR, Start_Time) [Hour]
-- ,Event_ID
-- ,CONVERT(VARCHAR(5), Start_Time, 114) + '-' + CONVERT(VARCHAR(5), End_Time, 114) [Start_End]
-- FROM CTE1

Applying different time period Groupings to a set of data

The following was a pattern I started to use two years ago and it is repeated over and over in my legacy code.
It effectively groups the same data using different time periods.
Is there a standard way I should be approaching this or is this long winded method as good as I'll get?
Another way of putting this question is how can the following be made more concise?
All 4 queries come out of the same data source and all four go into the same output table can these 4 queries be amalgamated into 1 shorter script?
DECLARE #myDate DATETIME = CONVERT(DATETIME,CONVERT(VARCHAR(11),GETDATE(),106));
DECLARE #myFirstDateLastMth CHAR(8) =CONVERT(CHAR(6),DATEADD(mm,-1,#myDate-1),112) + '01';
DECLARE #myFirstDateCurrentMth CHAR(8) =CONVERT(CHAR(6),DATEADD(mm,0,#myDate-1),112) + '01';
DELETE FROM WH.dbo.tb_myTable
--day on day==========
INSERT INTO WH.dbo.tb_myTable
SELECT
TimePeriod =
CASE
WHEN x.DateKey = CONVERT(VARCHAR(11),#myDate - 1,112) THEN 'Day'
WHEN x.DateKey = CONVERT(VARCHAR(11),#myDate - 2,112) THEN 'Day-1'
END,
Game = x.Name,
Score = SUM(x.Score),
Ticks = SUM(x.Ticks),
ScorePerTick = SUM(x.Score)/SUM(x.Ticks)
FROM #LimitedBetinfo x
WHEREx.DateKey >= CONVERT(VARCHAR(11),#myDate - 2,112)
GROUP BY
CASE
WHEN x.DateKey = CONVERT(VARCHAR(11),#myDate - 1,112) THEN 'Day'
WHEN x.DateKey = CONVERT(VARCHAR(11),#myDate - 2,112) THEN 'Day-1'
END,
x.Name;
--wk on wk==========
INSERT INTO WH.dbo.tb_myTable
SELECT
TimePeriod =
CASE
WHEN x.DateKey >= CONVERT(VARCHAR(11),#myDate - 7,112) THEN 'Week'
WHEN x.DateKey < CONVERT(VARCHAR(11),#myDate - 7,112)
AND x.DateKey >= CONVERT(VARCHAR(11),#myDate - 14,112)
THEN 'Week-1'
END,
Game = x.Name,
Score = SUM(x.Score),
Ticks = SUM(x.Ticks),
ScorePerTick = SUM(x.Score)/SUM(x.Ticks)
FROM #LimitedBetinfo x
WHERE x.DateKey >= CONVERT(VARCHAR(11),#myDate - 14,112)
GROUP BY
CASE
WHEN x.DateKey >= CONVERT(VARCHAR(11),#myDate - 7,112) THEN 'Week'
WHEN x.DateKey < CONVERT(VARCHAR(11),#myDate - 7,112)
AND x.DateKey >= CONVERT(VARCHAR(11),#myDate - 14,112)
THEN 'Week-1'
END,
g.Name;
--mth on mth==========
INSERT INTO WH.dbo.tb_myTable
SELECT
TimePeriod =
CASE
WHEN x.DateKey >= CONVERT(VARCHAR(11),#myDate - 28,112) THEN 'Month'
WHEN x.DateKey < CONVERT(VARCHAR(11),#myDate - 28,112)
AND x.DateKey >= CONVERT(VARCHAR(11),#myDate - 56,112)
THEN 'Month-1'
END,
Game = x.Name,
Score = SUM(x.Score),
Ticks = SUM(x.Ticks),
ScorePerTick = SUM(x.Score)/SUM(x.Ticks)
FROM #LimitedBetinfo x
WHERE x.DateKey >= CONVERT(VARCHAR(11),#myDate - 56,112)
GROUP BY
CASE
WHEN x.DateKey >= CONVERT(VARCHAR(11),#myDate - 28,112) THEN 'Month'
WHEN x.DateKey < CONVERT(VARCHAR(11),#myDate - 28,112)
AND x.DateKey >= CONVERT(VARCHAR(11),#myDate - 56,112)
THEN 'Month-1'
END,
g.Name;
--MTD and PrevCalMonth==========
INSERT INTO WH.dbo.tb_myTable
SELECT
TimePeriod
= CASE
WHEN x.DateKey >= #myFirstDateCurrentMth THEN 'MTD'
WHEN x.DateKey < #myFirstDateCurrentMth
AND x.DateKey >=#myFirstDateLastMth THEN 'PrevCalMonth'
END,
Game = x.Name,
Score = SUM(x.Score),
Ticks = SUM(x.Ticks),
ScorePerTick = SUM(x.Score)/SUM(x.Ticks)
FROM #LimitedBetinfo x
WHERE x.DateKey >= CONVERT(CHAR(6),DATEADD(mm,-1,#myDate-1),112) + '01'
GROUP BY
CASE
WHEN x.DateKey >= #myFirstDateCurrentMth THEN 'MTD'
WHEN x.DateKey < #myFirstDateCurrentMth
AND x.DateKey >=#myFirstDateLastMth THEN 'PrevCalMonth'
END,
g.Name;
I would make it a single insert statement.
Would prefer for now not to use the group by grouping sets, cube, or rollup as that I don't see how I could limit the rows calculated over individual day groups from being less than those calculated over larger time period groups.
So, to keep that from happening you could create a common-table-expression (;WITH mycte AS (...subquery...)), temp table, table variable, or XML formatted text object that would contain the time periods, one row/element for each.
This script can also be run with more or less time periods defined to get all results with only one trip from the app to the server.
Here's an example with temp table, that could also be easily made into a table variable:
--Define time periods
CREATE TABLE #TempTimePeriods (
TimePeriod VARCHAR(20) PRIMARY KEY,
TPBegin VARCHAR(11) NOT NULL,
TPEnd VARCHAR(11) NULL
);
DECLARE #myDate DATETIME = '2012-10-10';
DECLARE #myDateMinusOne DATETIME = DATEADD(dd, -1, #myDate);
INSERT INTO #TempTimePeriods ( TimePeriod, TPBegin, TPEnd )
SELECT [TimePeriod], CONVERT(VARCHAR(11), TPBegin, 112) TPBegin, CONVERT(VARCHAR(11), TPEnd, 112) TPEnd
FROM (
SELECT 'Day' [TimePeriod], #myDate - 1 TPBegin, #myDate - 1 TPEnd UNION ALL
SELECT 'Day-1' [TimePeriod], #myDate - 2 TPBegin, #myDate - 2 TPEnd UNION ALL
SELECT 'Week' [TimePeriod], #myDate - 7 TPBegin, NULL TPEnd UNION ALL
SELECT 'Week-1' [TimePeriod], #myDate - 14 TPBegin, #myDate - 8 TPEnd UNION ALL
SELECT 'Month' [TimePeriod], #myDate - 28 TPBegin, NULL TPEnd UNION ALL
SELECT 'Month-1' [TimePeriod], #myDate - 56 TPBegin, #myDate - 29 TPEnd UNION ALL
SELECT 'MTD' [TimePeriod], DATEADD(dd, -1 * DAY(#myDateMinusOne) + 1, #myDateMinusOne) TPBegin, NULL TPEnd UNION ALL
SELECT 'PrevCalMonth' [TimePeriod], DATEADD(mm,-1,DATEADD(dd, -1 * DAY(#myDateMinusOne) + 1, #myDateMinusOne)) TPBegin, DATEADD(dd, -1 * DAY(#myDateMinusOne), #myDateMinusOne) TPEnd
) TT;
And here is the main query...
--compute/insert results
INSERT INTO WH.dbo.tb_myTable
SELECT TimePeriods.TimePeriod,
x.Name Game,
SUM(x.Score) Score,
SUM(x.Ticks) Ticks,
CASE WHEN SUM(x.Ticks) != 0 THEN SUM(x.Score)/SUM(x.Ticks) END ScorePerTick
FROM #TempTimePeriods TimePeriods
--for periods with no data use left outer join to return 0-value results, otherwise inner join
LEFT OUTER JOIN #LimitedBetInfo x
ON x.DateKey >= [TimePeriods].TPBegin
AND (
[TimePeriods].TPEnd IS NULL
OR x.DateKey <= [TimePeriods].TPEnd
)
GROUP BY TimePeriods.TimePeriod, x.Name
You could also eliminate the the #TempTimePeriods table using a Common-Table-Expression below:
DECLARE #myDate DATETIME = '2012-10-10';
DECLARE #myDateMinusOne DATETIME = DATEADD(dd, -1, #myDate);
;WITH TimePeriods AS (
SELECT [TimePeriod], CONVERT(VARCHAR(11), TPBegin, 112) TPBegin, CONVERT(VARCHAR(11), TPEnd, 112) TPEnd
FROM (
SELECT 'Day' [TimePeriod], #myDate - 1 TPBegin, #myDate - 1 TPEnd UNION ALL
SELECT 'Day-1' [TimePeriod], #myDate - 2 TPBegin, #myDate - 2 TPEnd UNION ALL
SELECT 'Week' [TimePeriod], #myDate - 7 TPBegin, NULL TPEnd UNION ALL
SELECT 'Week-1' [TimePeriod], #myDate - 14 TPBegin, #myDate - 8 TPEnd UNION ALL
SELECT 'Month' [TimePeriod], #myDate - 28 TPBegin, NULL TPEnd UNION ALL
SELECT 'Month-1' [TimePeriod], #myDate - 56 TPBegin, #myDate - 29 TPEnd UNION ALL
SELECT 'MTD' [TimePeriod], DATEADD(dd, -1 * DAY(#myDateMinusOne) + 1, #myDateMinusOne) TPBegin, NULL TPEnd UNION ALL
SELECT 'PrevCalMonth' [TimePeriod], DATEADD(mm,-1,DATEADD(dd, -1 * DAY(#myDateMinusOne) + 1, #myDateMinusOne)) TPBegin, DATEADD(dd, -1 * DAY(#myDateMinusOne), #myDateMinusOne) TPEnd
) TT
)
INSERT INTO WH.dbo.tb_myTable
SELECT TimePeriods.TimePeriod,
x.Name Game,
SUM(x.Score) Score,
SUM(x.Ticks) Ticks,
CASE WHEN SUM(x.Ticks) != 0 THEN SUM(x.Score)/SUM(x.Ticks) END ScorePerTick
FROM [TimePeriods]
--for periods with no data use left outer join to return 0-value results, otherwise inner join
LEFT OUTER JOIN #LimitedBetInfo x
ON x.DateKey >= [TimePeriods].TPBegin
AND (
[TimePeriods].TPEnd IS NULL
OR x.DateKey <= [TimePeriods].TPEnd
)
GROUP BY [TimePeriods].TimePeriod, x.Name
And lastly you could define the time periods in an XML string-handy for passing to a stored procedure if that's your preference and proceed as follows:
--example XML string with time period definitions
DECLARE #TimePeriodsXml NVARCHAR(MAX) = '
<TimePeriod name="Day" tpbegin="20121010" tpend="20121010" />
<TimePeriod name="Day-1" tpbegin="20121009" tpend="20121009" />
<TimePeriod name="Week" tpbegin="20121004"/>
<TimePeriod name="Week-1" tpbegin="20120927" tpend="20121004" />
<TimePeriod name="Month" tpbegin="20120913" />
<TimePeriod name="Month-1" tpbegin="20120815" tpend="20120912" />
<TimePeriod name="MTD" tpbegin="20121001" />
<TimePeriod name="PrevCalMonth" tpbegin="20120901" tpend="20120930" />
';
and the main query modified to read the XML:
SELECT TimePeriods.TimePeriod,
x.Name Game,
SUM(x.Score) Score,
SUM(x.Ticks) Ticks,
CASE WHEN SUM(x.Ticks) != 0 THEN SUM(x.Score)/SUM(x.Ticks) END ScorePerTick
FROM (
SELECT
E.TimePeriod.value('./#name', 'VARCHAR(20)') TimePeriod,
E.TimePeriod.value('./#tpbegin', 'VARCHAR(20)') TPBegin,
E.TimePeriod.value('./#tpend', 'VARCHAR(20)') TPEnd
FROM (
SELECT CAST(#TimePeriodsXml AS XML) tpxml
) TT
CROSS APPLY tpxml.nodes('/TimePeriod') AS E(TimePeriod)
) TimePeriods
--for periods with no data use left outer join to return 0-value results, otherwise inner join
LEFT OUTER JOIN #LimitedBetInfo x
ON x.DateKey >= [TimePeriods].TPBegin
AND (
[TimePeriods].TPEnd IS NULL
OR x.DateKey <= [TimePeriods].TPEnd
)
GROUP BY TimePeriods.TimePeriod, x.Name
For an example of how the XML stringed query could be turned into a procedure, to support a single parameter of 1 or more time periods:
CREATE PROCEDURE dbo.GetTimePeriodAggregates
#TimePeriodsXmlString NVARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
SELECT TimePeriods.TimePeriod,
x.Name Game,
SUM(x.Score) Score,
SUM(x.Ticks) Ticks,
CASE WHEN SUM(x.Ticks) != 0 THEN SUM(x.Score)/SUM(x.Ticks) END ScorePerTick
FROM (
SELECT
E.TimePeriod.value('./#name', 'VARCHAR(20)') TimePeriod,
E.TimePeriod.value('./#tpbegin', 'VARCHAR(20)') TPBegin,
E.TimePeriod.value('./#tpend', 'VARCHAR(20)') TPEnd
FROM (
SELECT CAST(#TimePeriodsXml AS XML) tpxml
) TT
CROSS APPLY tpxml.nodes('/TimePeriod') AS E(TimePeriod)
) TimePeriods
LEFT OUTER JOIN #LimitedBetInfo x
ON x.DateKey BETWEEN TimePeriods.TPBegin AND TimePeriods.TPEnd
GROUP BY TimePeriods.TimePeriod, x.Name
END
Which could be run as:
--This declare is just an example, it could be instead a parameter passed from an application
DECLARE #ThisExecutionsXmlString NVARCHAR(MAX) = N'
<TimePeriod name="Day" tpbegin="20121010" tpend="20121010" />
<TimePeriod name="Day-1" tpbegin="20121009" tpend="20121009" />
<TimePeriod name="Week" tpbegin="20121004"/>
<TimePeriod name="Week-1" tpbegin="20120927" tpend="20121004" />
<TimePeriod name="Month" tpbegin="20120913" />
<TimePeriod name="Month-1" tpbegin="20120815" tpend="20120912" />
<TimePeriod name="MTD" tpbegin="20121001" />
<TimePeriod name="PrevCalMonth" tpbegin="20120901" tpend="20120930" />
';
INSERT INTO WH.dbo.tb_myTable
EXEC dbo.GetTimePeriodAggregates #TimePeriodsXmlString=#ThisExecutionsXmlString
You can create this stored procedure
CREATE PROCEDURE InsertData
#minLimit date,
#maxLimit date,
#minTerm nvarchar(50),
#maxTerm nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO tb_myTable
SELECT
[TimePeriod] = CASE WHEN x.DateKey >= #maxLimit THEN #maxTerm ELSE #minTerm END,
[Game] = x.Name,
[Score] = SUM(x.[Score]),
[Ticks] = SUM(x.[Ticks]),
[ScorePerTick] = SUM(x.[Score])/SUM(x.[Ticks])
FROM #LimitedBetinfo x
WHERE x.DateKey >= #minLimit
GROUP BY
CASE WHEN x.DateKey >= #maxLimit THEN #maxTerm ELSE #minTerm END,
x.Name
END
GO
And use like this
TRUNCATE TABLE tb_myTable
DECLARE #today date = cast(getdate() as date)
DECLARE #yesterday date = dateadd(day, -1, #today)
EXECUTE dbo.InsertData #yesterday, #today, N'Day-1', N'Day'
DECLARE #thisweek date = DATEADD(ww, DATEDIFF(ww,0,GETDATE()), 0)
DECLARE #lastweek date = DATEADD(ww, -1, #thisweek)
EXECUTE dbo.InsertData #lastweek, #thisweek, N'Week-1', N'Week'
DECLARE #prev28 date = dateadd(day, -28, #today)
DECLARE #prev56 date = dateadd(day, -56, #today)
EXECUTE dbo.InsertData #prev56, #prev28, N'Month-1', N'Month'
DECLARE #thismonth date = DATEADD(mm, DATEDIFF(mm,0,GETDATE()), 0)
DECLARE #lastmonth date = DATEADD(mm, -1, #thismonth)
EXECUTE dbo.InsertData #lastmonth, #thismonth, N'PrevCalMonth', N'MTD'
Use parameters - VALUES As a Table Source and apply them as parameters in CROSS APPLY with derived table
DECLARE #myDate datetime = CAST(GETDATE() AS date);
IF OBJECT_ID('WH.dbo.tb_myTable') IS NOT NULL DROP TABLE WH.dbo.tb_myTable
SELECT TimePeriod, Game, Score, Ticks, ScorePerTicks
INTO WH.dbo.tb_myTable
FROM (VALUES('Day', DATEADD(day, -1, #myDate), #myDate),
('Day-1', DATEADD(day, -2, #myDate), DATEADD(day, -2, #myDate)),
('Week', DATEADD(day, -7, #myDate), #myDate),
('Week-1', DATEADD(day, -14, #myDate), DATEADD(day, -8, #myDate)),
('Month', DATEADD(day, -28, #myDate), #myDate),
('Month-1', DATEADD(day, -56, #myDate), DATEADD(day, -29, #myDate)),
('MTD', DATEADD(DAY, 1 - DAY(#myDate), #myDate), #myDate),
('PrevCalMonth', DATEADD(DAY, 1 - DAY(#myDate), DATEADD(MONTH, -1, #myDate)), DATEADD(DAY, - DAY(#myDate), #myDate)))
RParameters(TimePeriod, BDate, EDate)
CROSS APPLY (SELECT x.Name AS Game,
SUM(x.Score) AS Score,
SUM(x.Ticks) AS Ticks,
SUM(x.Score) / SUM(x.Ticks) AS ScorePerTicks
FROM #LimitedBetinfo x
WHERE DateKey BETWEEN RParameters.BDate AND RParameters.EDate
GROUP BY Name) AS o
Demo on SQLFiddle
A possible improvement on fred's answer. Not in terms of speed, just readability / modifiability by removing the extra CASE. As a suggestion, I also replaced the passing of both strings (e.g. DAY and DAY-1) with a single string and to have the other just be a concat; this would however cause PrevCalMonth to be displayed as MTD-1 instead (though there are some work-arounds for this).
CREATE PROCEDURE InsertData
#minLimit date, #maxLimit date, #string nvarchar(50)
AS
INSERT INTO tb_myTable
SELECT TimePeriod, Name, SUM(Score) Score, SUM(Ticks) Ticks,
SUM(Score)/SUM(Ticks) ScorePerTick
FROM
(
SELECT *, /* or 'Name, Score, Ticks,' */
TimePeriod = CASE WHEN x.DateKey >= #maxLimit THEN #string ELSE #string+'-1' END
FROM #LimitedBetinfo x
WHERE x.DateKey >= #minLimit
) A
GROUP BY TimePeriod, Name
GO
And use like this:
TRUNCATE TABLE tb_myTable
DECLARE #today date = cast(getdate() as date)
DECLARE #yesterday date = dateadd(day, -1, #today)
EXECUTE dbo.InsertData #yesterday, #today, N'Day'
DECLARE #thisweek date = DATEADD(ww, DATEDIFF(ww,0,GETDATE()), 0)
DECLARE #lastweek date = DATEADD(ww, -1, #thisweek)
EXECUTE dbo.InsertData #lastweek, #thisweek, N'Week'
DECLARE #prev28 date = dateadd(day, -28, #today)
DECLARE #prev56 date = dateadd(day, -56, #today)
EXECUTE dbo.InsertData #prev56, #prev28, N'Month'
DECLARE #thismonth date = DATEADD(mm, DATEDIFF(mm,0,GETDATE()), 0)
DECLARE #lastmonth date = DATEADD(mm, -1, #thismonth)
EXECUTE dbo.InsertData #lastmonth, #thismonth, N'MTD'
It seems that this may be the job for CUBE groupings.
Sorry, I will not give you exact solution to your problem, but the MOCKUP form of select should be like:
select * from
(
select *,count(*) amount from
(
select datepart(HOUR, login_time) as hour,
datepart(MINUTE, login_time) as minute,
cmd as name
from sys.sysprocesses
) tmp
group by cube(tmp.hour, tmp.minute, tmp.name)
) tmp2
where tmp2.name is not null and
(
(tmp2.hour is not null and tmp2.minute is null) or
(tmp2.hour is null and tmp2.minute is not null)
)
One minus - that cube generates too much data for your problem here. So it needs to be filtered out. A big plus would be that you will only need just ONE select into temporary table.