get total orders for the last 1 month every week - sql-server

I have an "Orders" table containing column CreatedDate (datetime) on when the order took place.
Today is Feb 13, 2014.
How to get total records for the last 4 weeks for every week.
it should return something like this:
PerDate Total
2014-01-26 13 <--- sunday
2014-02-02 24 <--- sunday
2014-02-09 33 <--- sunday
2014-02-13 35 <--- this is today
13 from the first record is the total record from 2014-01-20 00:00:00 AM (monday) to 2014-01-26 12:00:00 PM (sunday)
24 from the 2nd record is the total record from 2014-01-27 00:00:00 AM (monday) to 2014-02-02 12:00:00 PM (sunday)
33 from the 3rd record is the total record from 2014-02-03 00:00:00 AM (monday) to 2014-02-09 12:00:00 PM (sunday)
35 from the 4th record is the total record from 2014-02-10 00:00:00 AM (monday) to 2014-02-13 (today)
so they are in Ascending order.

You should use DATEPART(dw,CreatedDate) function to calculate date of begin and end of the week for each CreatedDate and then just group by this field:
WITH T AS
(
SELECT
cast(floor(cast(CreatedDate as float)) as datetime)
-DATEPART(dw,CreatedDate)+1 as BeginOfweek,
cast(floor(cast(CreatedDate as float)) as datetime)
-DATEPART(dw,CreatedDate)+8 as EndOfWeek
FROM ORDERS
WHERE cast(floor(cast(CreatedDate as float)) as datetime) BETWEEN
DATEADD(WEEK,-4,GETDATE())
AND
GETDATE()
)
SELECT
BeginOfWeek,
MIN(CASE WHEN GETDATE()<EndOfWeek
THEN GETDATE()
ELSE EndOfWeek
END) as EndOfWeek,
Count(*) as OrdersCount
FROM T
Group by BeginOfWeek
SQLFiddle demo

Related

How to get the sum of each salary which is order by week?

I have a table like this
Input Table -
Date Salary
2020-01-01 00:00:00.000 2321
2020-01-02 00:00:00.000 2414
2020-01-03 00:00:00.000 2323
2020-01-04 00:00:00.000 2324
2020-01-05 00:00:00.000 2325.....so on
I have written a query but this query is only giving the sum of previous two weeks for which I have used LAG function
SELECT DATENAME(MONTH,Date) Months,
DATEPART(WEEK,Date) as WeekNo,
SUM(Salary) Salary,
WeekSalary= LAG(SUM(salary)) OVER (PARTITION BY Datepart(Month,Date) ORDER BY DATEPART(MONTH,Date))+SUM(salary)
FROM SheetTable
GROUP BY DATEPART(WEEK,Date),DATENAME(MONTH,Date)
Output:
Months Week Salary WeekSalary
January 1 9382 NULL
January 2 11681 21063
January 3 55245 66926
January 4 90939 146184
January 5 14091 105030
February 5 2352 NULL
February 6 16492 18844
February 7 16541 33033
February 8 16590 33131
February 9 16639 33229
March 10 16685 NULL
March 11 16730 33415
March 12 16779 33509
March 13 16828 33607
March 14 7227 24055
April 14 9650 NULL
April 15 7248 16898
but what if I need a column of total salary till week-
I tried this query
SELECT DATENAME(MONTH,Date) Months,
DATEPART(WEEK,Date) as WeekNo,
SUM(Salary) Salary,
TotalSalary=SUM(salary) OVER (ORDER BY Datepart(week,Date) ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
FROM SheetTable
GROUP BY DATEPART(WEEK,Date),DATENAME(MONTH,Date)
but this getting error:
Column 'SheetTable.salary' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Expected:
Months Week Salary TotalSalary
January 1 9382 9382 --Week(1)
January 2 11681 21063 --week(1+2)
January 3 55245 76308 --week(1+2+3)
January 4 90939 167247--week(1+2+3+4)...so on
You should be able to achieve what you need by using a frame like so:
SUM(SUM(salary)) OVER (ORDER BY Date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

Changing timesheet punch in and out query to a crosstab query

I am looking to create a crosstab query for a timeclock website I've made. Currently I'm just displaying the result in a table with each day as it's own line.
This is an example of the data.
id type user time
4941 1 user1 2017-10-03 11:24:00
4954 2 user1 2017-10-03 14:43:00
4955 1 user1 2017-10-03 14:43:00
4967 2 user1 2017-10-03 16:00:00
And here is the query that calculates the data for the current week.
SELECT user as UserName, CONVERT (varchar(10), time, 101) AS Date,
SUM(
CASE WHEN type = 1
THEN - 1 * (datepart(hh , [time]) + datepart(mi , [time]) / 60.0)
ELSE datepart(hh , [time]) + datepart(mi , [time]) / 60.0 END) AS Total
FROM table WHERE (username LIKE 'user1')
and datepart(wk, [time]) = datepart(wk, GETDATE())
GROUP BY user, CONVERT (varchar(10), time, 101) ORDER BY Date DESC
This displays data just like I wanted.
UserName Date Total
user1 08/21/2019 4.316667
user1 08/20/2019 9.366666
user1 08/19/2019 8.283333
However now I want to take that data and put it into a crosstab query so I can show the weeks on each row with the daily data in columns on that row. So far I've tried using a pivot to accomplish this.
SELECT Year, Month, Week, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
FROM (SELECT DATENAME(WEEKDAY, CONVERT (varchar(10), time, 101)) DAY, DATEPART(wk, CONVERT (varchar(10), _time, 101)) as Week
, DATEPART(M, CONVERT (varchar(10), time, 101)) as Month, DATEPART(YYYY, CONVERT (varchar(10), time, 101)) as Year
, SUM(
CASE
WHEN type = 1
THEN - 1 * (datepart(hh , [time]) + datepart(mi , [time]) / 60.0)
ELSE datepart(hh , [time]) + datepart(mi , [time]) / 60.0
END) AS Total
FROM table WHERE (username LIKE 'user1')
GROUP BY CONVERT(varchar(10), time, 101) ) p
PIVOT (SUM(Total)
FOR DAY IN (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday) ) pvt
ORDER BY Year, Month, Week DESC
And I have some success. The data seems to be displaying correctly. However when I try to ORDER BY more than one variable the display order is out of whack.
Year Month Week Monday Tuesday Wednesday Thursday Friday Saturday Sunday
2017 10 40 NULL 4.600000 0.000000 NULL NULL NULL NULL
2018 3 11 0.966667 NULL NULL NULL NULL NULL 5.150000
2019 7 31 NULL NULL 8.116667 NULL NULL NULL NULL
2019 8 34 8.283333 9.366666 -7.483333 NULL NULL NULL NULL
2019 8 33 8.166667 8.266667 8.083333 8.616668 8.883334 NULL NULL
2019 8 32 8.350000 8.333333 8.466666 7.883333 7.516666 NULL NULL
2019 8 31 NULL NULL NULL 8.833334 8.000001 NULL NULL
It should be sorting by Year, Week and Month. When I do just the year it works orders fine. But If I add in Week and Month it jumbles up the data in the wrong order. What am I doing wrong? It should look like this.
Year Week Month Monday Tuesday Wednesday Thursday Friday Saturday Sunday
2019 34 8 8.283333 9.366666 -7.483333 NULL NULL NULL NULL
2019 33 8 8.166667 8.266667 8.083333 8.616668 8.883334 NULL NULL
2019 32 8 8.350000 8.333333 8.466666 7.883333 7.516666 NULL NULL
2019 31 8 NULL NULL NULL 8.833334 8.000001 NULL NULL
2019 31 7 NULL NULL 8.116667 NULL NULL NULL NULL
2018 11 3 0.966667 NULL NULL NULL NULL NULL 5.150000
2017 40 10 NULL 4.600000 0.000000 NULL NULL NULL NULL
Also, how can I sum the week value to a totals column?

Performing operations in a Pivot

I am trying to implement a PIVOT but I am having trouble performing basic operations in it.
Current table:
week_no username days pick_count duration
------------------------------------------------
Week 50 Beck W Wednesday 227 7978
Week 50 Beck W Friday 320 7481
Week 50 Beck W Friday 282 5718
Week 50 Cockram D Thursday 165 10478
Week 50 Cowell P Thursday 145 14403
Week 50 Cowell P Thursday 159 7450
Week 50 Cowell P Friday 217 13101
...
Expected result:
week_no username monday tuesday wednesday thursday friday saturday sunday
--------------------------------------------------------------------------
Week 50 Beck W NULL NULL 102 NULL 164 NULL NULL
Week 50 Cockram D NULL NULL NULL 56 NULL NULL NULL
Week 50 Cowell P NULL NULL NULL 50 59 NULL NULL
...
The expected result should be calculated as followed: pick_count * 3600 / duration. That is the calculation I am having problem computing. When PIVOTing like so
SELECT
*
FROM
(
SELECT
week_no,
username,
days,
pick_count,
duration
FROM
table
) AS src
PIVOT
(
SUM(pick_count) * 3600 / SUM(duration) FOR days IN (monday, tuesday, wednesday, thursday, friday, saturday, sunday)
) AS pvt
I get Incorrect syntax near '*'.
PIVOT is not very flexible.
You can just use the old style cross tab approach.
SELECT week_no,
username,
SUM(CASE WHEN days = 'monday' then pick_count end) * 3600
/ SUM(CASE WHEN days = 'monday' then duration end) as monday,
SUM(CASE WHEN days = 'tuesday' then pick_count end) * 3600
/ SUM(CASE WHEN days = 'tuesday' then duration end) as tuesday
/*TODO: Add other five days*/
FROM YourTable
GROUP BY week_no,
username
I eventually found what I was looking for. Indeed, all I needed to do was to compute the calculation in the SELECT instead of the PIVOT.
SELECT
*
FROM
(
SELECT
week_no,
username,
days,
SUM(pick_count) * 3600 / SUM(duration) AS pick_rate
FROM
table
GROUP BY
week_no,
username,
days
) AS src
PIVOT
(
MAX(pick_rate) FOR days IN (monday, tuesday, wednesday, thursday, friday, saturday, sunday)
) AS pvt

sql server datepart return

I have a sql query that is grouping rows by calendar week
select count(*),datepart(wk,mydate)
from MyTable
where mydate between '12/26/2010' and '1/8/2011'
group by datepart(wk,mydate)
The date range is two weeks but three rows come back because Jan 1 is a saturday and is the only day in the range that DATEPART returns a 1 the other dates return 53 or 2.
I want jan 1 to be grouped with the dates that return a 53, but I want it to be a generic answer not something like CASE WHEN datepart(wk,mydate) = 53 then 1 else datepart(wk,mydate) end because that will work for that specific date range not for other years.
I'm just wondering what a good solution would be
thanks in advance.
We use to choose as week of a date, the week of his last sunday (first day of the week in SQL). So, for each date, you can ask for the week of his last sunday with the following query:
select count(*),datepart(wk,mydate-DATEPART(dw,mydate)+1)
from MyTable
where mydate between '12/26/2010' and '1/8/2011'
group by datepart(wk,mydate-DATEPART(dw,mydate)+1)
Perhaps you can use iso_week instead of wk.
select count(*),datepart(iso_week,mydate)
from MyTable
where mydate between '12/26/2010' and '1/8/2011'
group by datepart(iso_week,mydate)
Sample:
declare #T table (Val datetime)
insert into #T values
('2010-12-30'),
('2010-12-31'),
('2011-01-01'),
('2011-01-02'),
('2011-01-03'),
('2011-01-04'),
('2011-01-05')
select
Val,
datepart(iso_week, Val) as ISO_WEEK
from #T
Result:
Val ISO_WEEK
----------------------- -----------
2010-12-30 00:00:00.000 52
2010-12-31 00:00:00.000 52
2011-01-01 00:00:00.000 52
2011-01-02 00:00:00.000 52
2011-01-03 00:00:00.000 1
2011-01-04 00:00:00.000 1
2011-01-05 00:00:00.000 1
Try DateDiff() instead with your start date as the date to compare.

Calculate total running time from start/stop timestamps

I have a table containing a number of timestamps per day, they represents start and stop events.
ID TimeStamp
----------------------
1 2008-01-01 07:00:00
1 2008-01-01 08:15:00
1 2008-01-01 10:00:00
1 2008-01-01 11:00:00
1 2008-01-02 10:30:00
1 2008-01-02 12:00:00
I would like to calcuate the total running time per day, like this:
ID Date RunningTime
-------------------------
1 2008-01-01 02:15:00
1 2008-01-02 01:30:00
Do anyone have a nice T-SQL solution for my problem?
WITH q AS
(
SELECT *,
CONVERT(DATETIME, CONVERT(VARCHAR(8), TimeStamp, 112), 112) AS dte,
ROW_NUMBER() OVER (PARTITION BY id, CONVERT(DATETIME, CONVERT(VARCHAR(8), TimeStamp, 112), 112) ORDER BY TimeStamp) AS rn
FROM mytable
)
SELECT qb.id, qb.dte, SUM(DATEDIFF(second, qb.TimeStamp, qe.TimeStamp))
FROM q qb
JOIN q qe
ON qe.id = qb.id
AND qe.dte = qb.dte
AND qe.rn = qb.rn + 1
WHERE qb.rn % 2 = 1
GROUP BY
qb.id, qb.dte
This assumes that every record open on a certain day should also be closed on the same day.

Resources