Get average number during period - database

I have a database that stores data from the stock market.
There is a table with 3 columns: stockId, date, and volume
New data will be inserted into the table every trading day.
How can I get a result like 'Average volume for each stock over the last 10 trading days'?

SELECT AVG(volume) FROM mytable WHERE date >= (CURDATE() - INTERVAL 10 DAY)
EDIT:
Last 10 day groups, and their averages.
SELECT AVG(volume) FROM mytable GROUP BY date ORDER BY date DESC LIMIT 10

http://sqlfiddle.com/#!6/c8dbb/4
CREATE TABLE Stocks
([StockId] int, [Date] DateTime, [Volume] int)
;
INSERT INTO Stocks
([StockId], [Date], [Volume])
VALUES
(1, GetDate(), 1000),
(1, GetDate()+1, 2000),
(1, GetDate()+2, 4000),
(2, GetDate(), 1000),
(2, GetDate()+1, 1000),
(2, GetDate()+2, 500)
;
Select StockId, AVG(Volume) [AverageVolume]
FROM Stocks
WHERE [Date] >= DATEADD(dd, 0, DATEDIFF(dd, 0, GetDate())) - 10
Group by StockId
Order by StockId

SELECT SUM(volume)/10 FROM table_name
Where date Between Cast('7/18/13 12:01:01' As DateTime) And Cast('7/08/13 12:01:01' as DateTime)

I'm basing this off of Dodecapus answer and based off of comments you've given to other answers. I'm just including query in answer but check out sqlfiddle for working example with data.
http://sqlfiddle.com/#!6/91599/2
SELECT
StockId
,AVG(Volume) [AverageVolume]
FROM Stocks
WHERE [Date] IN
(
SELECT DISTINCT TOP 10 [Date] FROM Stocks ORDER BY [Date] DESC
)
GROUP BY StockId
ORDER BY StockId
This will only work if there is a record of at least one stock with volume per trading day.

Fun little query to write. Here it is:
SELECT AVG(x.Volume) FROM (SELECT Volume FROM StockTable WHERE Date BETWEEN
DATE_ADD(NOW(), INTERVAL -10 DAY) AND NOW())x
This is what I used to build a sample table to work off of in SQLFiddle:
CREATE TABLE StockTable (ID INT PRIMARY KEY AUTO_INCREMENT NOT NULL, Date DATETIME, Volume INT);
INSERT INTO StockTable (Date, Volume) VALUES (DATE_ADD(NOW(), INTERVAL 12 DAY), 1000), (DATE_ADD(NOW(), INTERVAL 1 DAY), 5000),
(DATE_ADD(NOW(), INTERVAL 0 DAY), 3000), (DATE_ADD(NOW(), INTERVAL -11 DAY), 6000), (DATE_ADD(NOW(), INTERVAL -5 DAY), 4000), (DATE_ADD(NOW(), INTERVAL 7 DAY), 9000);
Here is a link to the SQLFiddle of the query in action.
Idea behind the query: I create a derived table x which contains just the volumes within the past 10 days. Then I calculate the average of the volumes contained in that table. VoilĂ !
EDIT:
I realized specifically what you are looking for after reading through the other answers and comments. You are looking to get the average for each stock in the stock market over the last 10 days.
I built the sample table off of this:
CREATE TABLE StockTable (StockId INT NOT NULL, Date DATETIME, Volume INT);
INSERT INTO StockTable (StockId, Date, Volume) VALUES (1, DATE_ADD(NOW(), INTERVAL 6
DAY), 1000), (2, DATE_ADD(NOW(), INTERVAL 1 DAY), 5000),
(2, DATE_ADD(NOW(), INTERVAL 0 DAY), 3000), (3, DATE_ADD(NOW(), INTERVAL -8 DAY),
6000), (1, DATE_ADD(NOW(), INTERVAL -5 DAY), 4000),
(2, DATE_ADD(NOW(), INTERVAL 7 DAY), 9000);
And the query to get your results are:
SELECT StockId, AVG(Volume) FROM StockTable WHERE Date BETWEEN DATE_ADD(NOW(),
INTERVAL -10 DAY) AND NOW() GROUP BY StockId
Here is a link to the SQLFiddle of the query in action.

Related

Splitting a Date from hours and mins timestamp

In snowflake, I have a date time stamp. '2022-07-18 08:00:00"
How do I separate the day from the time? I want to group by the day, but cant because of the time.
Thank you.
In Snowflake you can use the DAY or DATE functions, e.g.
create a test table
create or replace table table_with_dates (ID number, DATE timestamp);
insert values
insert into table_with_dates values (1, '2022-07-18 08:00:00'),
(2, '2022-07-18 08:00:00'),
(3, '2022-07-18 08:00:00'),
(1, '2022-07-19 08:00:00'),
(2, '2022-07-19 08:00:00'),
(1, '2022-07-20 08:00:00'),
(2, '2022-07-20 08:00:00'),
(1, '2022-07-21 08:00:00');
select the data grouping by the DATE part
select date(DATE), count(*) from table_with_dates
group by date(DATE);
select the date grouping by the DAY part
select DAY(DATE), count(*) from table_with_dates
group by DAY(DATE);
So the simplest way is to cast to DATE
some data in a CTE so work against:
with data(timestamp) as (
select column1::timestamp
from values
('2022-07-18 08:00:00'),
('2022-07-18 08:00:00'),
('2022-07-18 08:00:00'),
('2022-07-19 08:00:00'),
('2022-07-19 08:00:00'),
('2022-07-20 08:00:00'),
('2022-07-20 08:00:00'),
('2022-07-21 08:00:00')
)
select
d.timestamp::date as date
,count(*) as count
from data as d
group by 1
order by 1;
gives:
DATE
COUNT
2022-07-18
3
2022-07-19
2
2022-07-20
2
2022-07-21
1
DATE_TRUNC with DAY gives the same results, but is a little verbose.
select
date_trunc('day', d.timestamp::date) as date
,count(*) as count
from data as d
group by 1
order by 1;
DATE
COUNT
2022-07-18
3
2022-07-19
2
2022-07-20
2
2022-07-21
1

Find the date when a milestone was achieved

I have people that do many multi-day assignments (date x to date Y). I would like to find the date that they completed a milestone e.g. 50 days work completed.
Data is stored as a single row per Assignment
AssignmentId
StartDate
EndDate
I can sum up the total days they have completed up to a date, but am struggling to see how I would find out the date that a milestone was hit. e.g. How many people completed 50 days in October 2020 showing the date within the month that this occurred?
Thanks in advance
PS. Our database is SQL Server.
As mentioned by prwvious comments, it would be much easier to help you if you could provide example data and table structure in order help you answer this question.
However, guessing a simple DB structure with a table for your peolple, your tasks and the work each user completed, you can get the required sum of days by use of a date table (or cte) which contains a entry for each day and the window function SUM with UNBOUNDED PRECEDING. Following an example:
DECLARE #people TABLE(
id int
,name nvarchar(50)
)
DECLARE #tasks TABLE(
id int
,name nvarchar(50)
)
DECLARE #work TABLE(
people_id int
,task_id int
,task_StartDate date
,task_EndDate date
)
INSERT INTO #people VALUES (1, 'Peter'), (2, 'Paul'), (3, 'Mary');
INSERT INTO #tasks VALUES (1, 'Devleopment'), (2, 'QA'), (3, 'Sales');
INSERT INTO #work VALUES
(1, 1, '2019-04-05', '2019-04-08')
,(1, 1, '2019-05-05', '2019-06-08')
,(1, 1, '2019-07-05', '2019-09-08')
,(2, 2, '2019-04-08', '2019-06-08')
,(2, 2, '2019-09-08', '2019-10-03')
,(3, 1, '2019-11-01', '2019-12-01')
;WITH cte AS(
SELECT CAST('2019-01-01' AS DATE) AS dateday
UNION ALL
SELECT DATEADD(d, 1, dateday)
FROM cte
WHERE DATEADD(d, 1, dateday) < '2020-01-01'
),
cteWorkDays AS(
SELECT people_id, task_id, dateday, 1 AS cnt
FROM #work w
INNER JOIN cte c ON c.dateday BETWEEN w.task_StartDate AND w.task_EndDate
),
ctePeopleWorkdays AS(
SELECT *, SUM(cnt) OVER (PARTITION BY people_id ORDER BY dateday ROWS UNBOUNDED PRECEDING) dayCnt
FROM cteWorkDays
)
SELECT *
FROM ctePeopleWorkdays
WHERE dayCnt = 50
OPTION (MAXRECURSION 0)
The solution depends on how you store your data. The solution below assumes that each worked day exists as a single row in your data model.
The approach below uses a common table expression (cte) to generate a running total (Total) for each person (PersonId) and then filters on the milestone target (I set it to 5 to reduce the sample data size) and target month.
Sample data
create table WorkedDays
(
PersonId int,
TaskDate date
);
insert into WorkedDays (PersonId, TaskDate) values
(100, '2020-09-01'),
(100, '2020-09-02'),
(100, '2020-09-03'),
(100, '2020-09-04'),
(100, '2020-09-05'), -- person 100 worked 5 days by 2020-09-05 = milestone (in september)
(200, '2020-09-29'),
(200, '2020-09-30'),
(200, '2020-10-01'),
(200, '2020-10-02'),
(200, '2020-10-03'), -- person 200 worked 5 days by 2020-10-03 = milestone (in october)
(200, '2020-10-04'),
(200, '2020-10-05'),
(200, '2020-10-06'),
(300, '2020-10-10'),
(300, '2020-10-11'),
(300, '2020-10-12'),
(300, '2020-10-13'),
(300, '2020-10-14'), -- person 300 worked 5 days by 2020-10-14 = milestone (in october)
(300, '2020-10-15'),
(400, '2020-10-20'),
(400, '2020-10-21'); -- person 400 did not reach the milestone yet
Solution
with cte as
(
select wd.PersonId,
wd.TaskDate,
count(1) over(partition by wd.PersonId
order by wd.TaskDate
rows between unbounded preceding and current row) as Total
from WorkedDays wd
)
select cte.PersonId,
cte.TaskDate as MileStoneDate
from cte
where cte.Total = 5 -- milestone reached
and year(cte.TaskDate) = 2020
and month(cte.TaskDate) = 10; -- in october
Result
PersonId MilestoneDate
-------- -------------
200 2020-10-03
300 2020-10-14
Fiddle (also shows the common table expression output).

Grouping by shifted DATETIME field and PIVOT by ID

I'm having table with schema (simplified):
CREATE TABLE [Test]
(
CaptureTime DATETIME,
SnapShotValue INT,
Id INT
);
With following 30 minute data:
And I want calculate average value for every HH:00 hour data take values HH:30 and HH+1:00 values and PIVOT them. For test data above:
I'm starting here and how to group values HH:00 hour data take values HH:30 and HH+1:00 values and Pivot? Thank you!
If I follow you correctly, you can offset the capture time by 30 minutes, then remove the minutes, and finally do conditional aggregation:
select dateadd(minute, - datepart(minute, v.capturetime), v.capturetime) capture_time,
avg(case when id = 1 then 1.0 * snapshotvalue end) avg1,
avg(case when id = 2 then 1.0 * snapshotvalue end) avg2
from test t
cross apply (values (dateadd(minute, - 30, capturetime))) v(capturetime)
group by dateadd(minute, - datepart(minute, v.capturetime), v.capturetime)
Demo on DB Fiddle

Time Duration for staff on a night shift with onguard system accesscontrol database

I am using the Lenel Onguard with SQL server dBase to make the time attendance system for our employees.
I summarize each day's transaction to make their first entry and last exit for each day and get the datediff. to get the time duration. But the problem is with night shift employees, it is showing the time out which happened in the morning of the same day where actual exit is on the next day. so the datediff. returning with wrong value. Any solutions are most welcomed!
This code gives me the wrong value for night shift.can anyone help me out to modify the code to fit staff on day shift and those on night shift in which their exit time is on next day
SELECT DISTINCT
BADGE.ID,
UPPER(ISNULL(dbo.EMP.FIRSTNAME, ' ') + ' ' + ISNULL(dbo.EMP.LASTNAME, ' ') + ' ' + ISNULL(dbo.EMP.MIDNAME, ' '))AS NAMES,
A.*,
B.TIMEOUT,
datediff(hour,a.[TIMEIN],b.TIMEOUT) HoursWorked
FROM (
SELECT empid,convert(date,event_time_utc)[Date],ltrim(right(convert(varchar(25), DATEADD(HOUR,3,CAST(min(event_time_utc)AS TIME)), 100), 7)) TIMEIN
FROM events INNER JOIN READER ON EVENTS.DEVID=READER.READERID INNER JOIN EVENT ON EVENTS.EVENTTYPE=EVENT.EVTYPEID AND EVENTS.EVENTID=EVENT.EVID
WHERE READERID=19 AND PANELID=16 AND EVDESCR='Access Granted'
GROUP BY empid,convert(date,event_time_utc)
) A
JOIN
(
SELECT empid,convert(date,event_time_utc)[Date],ltrim(right(convert(varchar(25), DATEADD(HOUR,3,CAST(MAX(event_time_utc)AS TIME)), 100), 7)) TIMEOUT
FROM events INNER JOIN READER ON EVENTS.DEVID=READER.READERID INNER JOIN EVENT ON EVENTS.EVENTTYPE=EVENT.EVTYPEID AND EVENTS.EVENTID=EVENT.EVID
WHERE READERID=20 AND PANELID=16 AND EVDESCR='Access Granted'
GROUP BY empid,convert(date,event_time_utc)
) B on A.empid=b.empid and a.[Date]=b.[Date]
JOIN Emp on emp.id=A.EmpID
JOIN BADGE ON BADGE.EMPID=A.EMPID
ORDER BY DATE
Results
EmpID TIMEIN Timeout
1 2014-08-21 21:38:06.000 2014-08-22 06:00:10.000
2 2014-08-22 22:30:00.000 2014-08-23 06:00:10.000
In summary you have Event/s table, that have EmpId, the datetime of each scan, and there is no info about TimeOut or TimeIn, and you want to find that, well from the information you provided its a bit hard, Im sure you have more data that will help make this simpler, like the shift hours, any limitations, is over hours accepted and more boundary information.
Lets say you dont, so we will need to put some assumptions, for example, as the employees work in shifts, I will assume that the shift is 8-10 hours, and if I see a gab in scanning more than 14 hours that the employee went home, I will not care if he is a night shift employee or a day shift, if there is a gab between two sequentialscans more than 14 hours that mean he went home, or in other words that is a TimeOut, and then next entry is a TimeIn.
You did not provide any table structure or data, so I will ignore your query and focus on the problem you want to solve, so I will assume I have only one Events Table that have all the data, you can adapt this to your query if this helps you.
I will create a memory table here and fill it with EmpId 1, that is a on the day shift and EmpId 2 that is on the night shift, I will assume some data and do some calculations.
Declare #Events TABLE(
EmpId int,
event_time_utc datetime
)
insert into #Events values
(1, '2014-08-21 07:38:06.000'),--first day for emp1
(1, '2014-08-21 08:39:06.000'),
(1, '2014-08-21 14:44:06.000'),
(1, '2014-08-21 15:38:06.000'),
(1, '2014-08-21 16:01:06.000'),
(1, '2014-08-22 07:40:06.000'),--second day for emp1
(1, '2014-08-22 08:50:06.000'),
(1, '2014-08-22 14:30:06.000'),
(1, '2014-08-22 15:30:06.000'),
(1, '2014-08-22 16:05:06.000'),
(1, '2014-08-23 07:38:06.000'),--3rd day for emp1
(1, '2014-08-23 08:39:06.000'),
(1, '2014-08-23 14:44:06.000'),
(1, '2014-08-23 15:38:06.000'),
(1, '2014-08-23 16:01:06.000'),
(1, '2014-08-24 07:40:06.000'),--4th day for emp1
(1, '2014-08-24 08:50:06.000'),
(1, '2014-08-24 14:30:06.000'),
(1, '2014-08-24 15:30:06.000'),
(1, '2014-08-24 16:05:06.000'),
(2, '2014-08-21 21:38:06.000'),--first day for emp2 -- night shift
(2, '2014-08-21 23:38:06.000'),
(2, '2014-08-22 01:38:06.000'),
(2, '2014-08-22 04:05:06.000'),
(2, '2014-08-22 21:38:06.000'),--first day for emp2 -- night shift
(2, '2014-08-22 23:38:06.000'),
(2, '2014-08-23 01:38:06.000'),
(2, '2014-08-23 04:05:06.000'),
(2, '2014-08-23 21:38:06.000'),--3rd day for emp2 -- night shift
(2, '2014-08-23 23:38:06.000'),
(2, '2014-08-24 01:38:06.000'),
(2, '2014-08-24 04:05:06.000'),
(2, '2014-08-24 21:38:06.000'),--4th day for emp2 -- night shift
(2, '2014-08-24 23:38:06.000'),
(2, '2014-08-25 01:38:06.000'),
(2, '2014-08-25 04:05:06.000')
Now I will use the below CTEs to figure out the TimeIn and TimeOut and calculate the hours.
;with cte as (
--get the next entry, and set a row number based on EmpID and time
select *
,LEAD(event_time_utc,1) over (partition by EmpId order by event_time_utc) nextEntry
,ROW_NUMBER() over (partition by EmpId order by event_time_utc) seq
from #Events
),cte2 as (
--count the hours between this entry and the one after
select *,datediff(hour,event_time_utc,nextEntry) [hours] from cte
),cte3 as (
--if gab more then 14 or if its null, set it as time in
select *
,case when seq=1 then event_time_utc
when [hours]>14 then nextEntry
else null end [TimeIn]
from cte2
),cte4 as (
--find the seq for the Timeout
select *,
Isnull(
lead(seq) over (partition by EmpId order by event_time_utc)
,(select top(1) cte.seq from cte where cte.EmpId=cte3.EmpId order by event_time_utc desc)) [TimeOutSeq]
from cte3 where TimeIn is not null
),cte5 as (
--convert the seq to timeout by joining to the same table using the TimeOutSeq to help
select cte4.*,cte3.event_time_utc [TimeOut] from cte4
left outer join cte3 on cte3.seq=cte4.TimeOutSeq and cte3.EmpId=cte4.EmpId
)
--select * from cte3
--finally show the needed fileds only, and the hours for each employee
select EmpId,seq,TimeIn,[TimeOut],datediff(Hour,TimeIn,[TimeOut]) [hours] from cte5 order by EmpId, TimeIn
The result for my set of data is as below:-
EmpId Seq TimeIn TimeOut hours
1 1 2014-08-21 07:38:06.000 2014-08-21 16:01:06.000 9
1 5 2014-08-22 07:40:06.000 2014-08-22 16:05:06.000 9
1 10 2014-08-23 07:38:06.000 2014-08-23 16:01:06.000 9
1 15 2014-08-24 07:40:06.000 2014-08-24 16:05:06.000 9
2 1 2014-08-21 21:38:06.000 2014-08-22 04:05:06.000 7
2 4 2014-08-22 21:38:06.000 2014-08-23 04:05:06.000 7
2 8 2014-08-23 21:38:06.000 2014-08-24 04:05:06.000 7
2 12 2014-08-24 21:38:06.000 2014-08-25 04:05:06.000 7

Gather cumulative weekly sales using SQLServer management studio

My query gather a technician daily sales data.
select
SUM(O.SUB_TOTAL) AS TOTALSALES,
COUNT(DISTINCT O.ORDER_NO) AS BILLABLEORDERS
FROM ordhdr o
INNER JOIN schedule s ON s.ID_VAL = o.ORDER_NO
WHERE
s.DATE = Convert(varchar(10), GETDATE()-1,121)
AND O.[TYPE] = 'SVC'
However, I also want to get weekly cumulative sales to know whether he is on track or not for his weekly numbers but I struggling transforming the query.
This has to reset for each Sunday or Monday so I cannot use a CurrentDate-7 function.
I don't know how to only look at a CURRENT weeks data using SQL-Server Management Studio.
Look into the 'DatePart' function. You can use it to identify which week out of the year a given date resides in, and it seems to turn over on Sunday. For instance:
datepart(week, '2019-07-06') -- Saturday, returns 27
datepart(week, '2019-07-07') -- Sunday, returns 28
That alone should get you going. However, you can throw in a few more techniques to get all the information in one resultset.
Consider the following ordhdr table:
declare #ordhdr table (
order_no int,
sub_total decimal(8,2),
type varchar(15)
);
insert #ordhdr values
(1, 23.25, 'svc'),
(2, 324.23, 'svc'),
(3, 423.89, 'svc'),
(4, 324.80, 'svc'),
(5, 234.23, 'svc'),
(6, 923.23, 'svc');
... and the following schedule table:
declare #schedule table (id_val int, date date);
insert #schedule values
(1, '2019-07-04'),
(2, '2019-07-04'),
(3, '2019-07-08'),
(4, '2019-07-09'),
(5, '2019-07-09'),
(6, '2019-07-10');
Well, using datepart, datename, cross apply, and grouping sets, you can do this:
select ap.year,
ap.weekOfYear,
dayOfWeek =
case
when ap.weekOfYear is null then '<entire year>'
when ap.dayOfWeek is null then '<entire week>'
else ap.dayOfWeek
end,
s.date,
totalsales = sum(o.sub_total),
billableorders = count(distinct o.order_no)
from #ordhdr o
join #schedule s on s.id_val = o.order_no
cross apply (select
year = datepart(year, s.date),
weekOfYear = datepart(week, s.date),
dayOfWeek = datename(weekday, s.date)
) ap
where o.type = 'svc'
group by grouping sets (
(ap.year, ap.weekOfYear, ap.dayOfWeek, s.date),
(ap.year, ap.weekOfYear),
(ap.year)
)
order by weekOfYear, date
Which will give you daily, weekly, and yearly totals.

Resources