sql sum with separate column for each day - sql

My current code looks like this:
declare #start datetime
declare #end datetime
set #start = '2/16/2020'
set #end = '2/19/2020'
select
s.location, s.department, s.position, SUM(s.hours)/60
from SCHEDULES s where SCHDATE between #start and #end
group by s.location, s.department, s.position
It yields the following results (which is correct):
loc dep pos hrs
2 2 7 96
3 2 11 96
2 2 13 192
3 2 5 96
3 1 4 228
How do I break this out by day so that the format looks like below:
'start' is the #start variable and 'start+1' is simply that plus 1 day, etc.
loc dep pos start start+1 start+2 start+3
2 2 7 24 24 24 24
3 2 11 24 24 24 24
2 2 13 48 48 48 48
3 2 5 24 24 24 24
3 1 4 57 57 57 57
thanks

Sounds like you want to do a pivot:
SELECT *
FROM SCHEDULES s
PIVOT(
SUM(hours)
FOR SCHDATE IN (
[2020-2-16],
[2020-2-17],
[2020-2-18],
[2020-2-19])
) AS pivot_table;
Hopefully the dates you want to work with are fixed and known. If you need to pivot on calculated columns, things seem to get a lot more complicated. For example, see this thread.

Related

Display rows where multiple columns are different

I have data that looks like this. Thousands of rows returned, but this is just a sample.
Most days have the same numbers in them, but some do not. Note that ID 1 and 5 have identical numbers every day.
ID
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
1
26
26
26
26
26
26
26
2
44
44
30
30
44
44
44
3
55
55
55
55
80
90
55
4
12
12
43
43
43
43
43
5
36
36
36
36
36
36
36
I'd like to only return rows where the days of the week have different numbers.
In this case, the only IDs returned should be 2, 3 & 4.
What would I want this query to look like?
Thanks!
One idea that should work in most RDBMS (with some syntax tweaks) is the following.
This is SQL Server compatible: pivot the days into rows and count the distinct values and filter accordingly:
select id
from t
cross apply (
select Count(distinct d) from (
values(sunday),(monday),(tuesday),(wednesday),(thursday),(friday),(saturday)
)d(d)
)d(v)
where d.v>1

T-SQL go through Dates

I have the following table:
Column1 Column2 Column3
04/07/2019 1
04/08/2019 2
04/09/2019 8
04/10/2019 9
04/11/2019 15
04/12/2019 16
04/13/2019 5
04/14/2019 6
04/15/2019 8
04/16/2019 9
04/17/2019 10
04/18/2019 11
04/19/2019 5
04/20/2019 5
04/21/2019 8
04/22/2019 8
04/23/2019 9
04/24/2019 10
04/25/2019 11
04/26/2019 12
04/27/2019 10
I need to find out a way to iterate through the values in column one and identify weeks which should start from Saturday - Sunday. So, in this example one iteration should be from the 14 - 20th. Or another iteration would be from the 7th through the 13th which is Saturday - Sunday. Then After identifying each week, I need to do some calculation on the other columns.The calculation would be updating Column3 if the total amount for Column2 within 1 week (Based on Column1 Saturday to Sunday) exceeds 40 or not. Then the same for the next iteration of week (Saturday - Sunday).
Desired Results:
Column1 Column2 Column3
04/07/2019 1 56
04/08/2019 2 56
04/09/2019 8 56
04/10/2019 9 56
04/11/2019 15 56
04/12/2019 16 56
04/13/2019 5 56
04/14/2019 6 54
04/15/2019 8 54
04/16/2019 9 54
04/17/2019 10 54
04/18/2019 11 54
04/19/2019 5 54
04/20/2019 5 54
04/21/2019 8 68
04/22/2019 8 68
04/23/2019 9 68
04/24/2019 10 68
04/25/2019 11 68
04/26/2019 12 68
04/27/2019 10 68
Please note: The data can range from 3 weeks to a few month. So, the code needs to capture the weeks for any specific range.
You can use datepart() to get the week of a date. You can then use the week to partition by in a windowed sum(). From there you can UPDATE the table joining a derived table that gets the sum like mentioned before. To make sure the week begins on Sunday issue a SET DATEFIRST 7 before the UPDATE.
SET DATEFIRST 7;
UPDATE t1
SET t1.column3 = t3.column3
FROM elbat t1
INNER JOIN (SELECT t2.column1,
sum(t2.column2) OVER (PARTITION BY datepart(week, t2.column1)) column3
FROM elbat t2) t3
ON t3.column1 = t1.column1;
db<>fiddle

Aggregate result from query by quarter SQL

Lets say I have a table which holds all exports for some time back in Microsoft SQL database:
Name:
ExportTable
Columns:
id - numeric(18)
exportdate - datetime
In order to get the number of exports per week I can run the following query:
SELECT DATEPART(ISO_WEEK,[exportdate]) as 'exportdate', count(exportdate) as 'totalExports'
FROM [ExportTable]
Group By DATEPART(ISO_WEEK,[exportdate])
order by exportdate;
Returns:
exportdate totalExports
---------- ------------
27 13
28 12
29 15
30 8
31 17
32 10
33 7
34 15
35 4
36 18
37 10
38 14
39 14
40 21
41 19
Would it be possible to aggregate the week results by quarter so the output becomes something like the bellow?
UPDATE
Sorry for not being crystal clear, I would like the current result to add upp with previous result up to a new quarter.
Note week 41 contains 21+19 = 40
Week 39 contains 157 (13+12+15+8+17+10+7+15+4+18+10+14+14)
exportdate totalExports Quarter
---------- ------------ -------
27 13 3
28 25 3
29 40 3
30 48 3
31 65 3
32 75 3
33 82 3
34 97 3
35 101 3
36 119 3
37 129 3
38 143 3
39 157 3 -- Sum of 3 Quarter values.
40 21 4 -- New Quarter show current week value
41 40 4 -- (21+19)
You can use this.
SELECT
DATEPART(ISO_WEEK,[exportdate]) as 'exportdate'
, SUM( count(exportdate) ) OVER ( PARTITION BY DATEPART(QUARTER,MIN([exportdate])) ORDER BY DATEPART(ISO_WEEK,[exportdate]) ROWS UNBOUNDED PRECEDING ) as 'totalExports'
, DATEPART(QUARTER,MIN([exportdate])) [Quarter]
FROM [ExportTable]
Group By DATEPART(ISO_WEEK,[exportdate])
order by exportdate;
You could use a case statement to separate the dates into quarters.
e.g.
CASE
WHEN EXPORT_DATE BETWEEN '1' AND '4' THEN 1
WHEN Export_Date BETWEEN '5' and '9' THEN 2
ELSE 0 AS [Quarter]
END
Its just an example but you get the idea.
You could then use the alias from the case
SELECT DATEPART(ISO_WEEK,[exportdate]) as 'exportdate', count(exportdate) as 'totalExports', DATEPART(quarter,[exportdate]) as quarter FROM [ExportTable] Group By DATEPART(ISO_WEEK,[exportdate]), DATEPART(quarter,[exportdate]) order by exportdate;

Calculate Sub Query Column Based On Calculated Column

I have a table ScheduleRotationDetail that contains these as columns:
ScheduleRotationID ScheduleID Ordinal Duration
379 61 1 1
379 379 2 20
379 512 3 1
379 89 4 20
I have a query that goes like this in order to get the day of the year each schedule is supposed to start on:
SELECT ScheduleID, Ordinal, Duration,
,Duration * 7 AS DurationDays
,( SELECT ( ISNULL( SUM(ISNULL( Duration, 0 )), 0 ) - 1 ) * 7
FROM ScheduleRotationDetail WHERE ScheduleRotationID = srd.ScheduleRotationID
AND Ordinal <= srd.Ordinal ) AS StartDay
FROM ScheduleRotationDetail srd
WHERE srd.ScheduleRotationID = 379
That outputs this as the result set:
ScheduleID Ordinal Duration DurationDays StartDay
61 1 1 7 0
379 2 20 140 140
512 3 1 7 147
89 4 20 140 287
Yet what I need the start day column values to be are:
0
7
147
154
I have tried CTEs but can't get it to work so I've come to here for advice.
It looks like you want a cumulative sum. In SQL Server 2012+, you can do:
SELECT ScheduleID, Ordinal, Duration,
SUM(Duration*7) OVER (ORDER BY Ordinal) - Duration*7 as StartDate
FROM ScheduleRotationDetail srd ;
In earlier versions, you can use APPLY for this purpose (or a correlated subquery).

convert datediff minutes to 100 base format in sql

I want to calculate date time difference between two dates but the minutes should be in .100 scale i.e if date time difference is 2.30 (2 Hours 30 Minutes) i want it in format 2.50
30 minutes = 0.50
i wrote a query for it but it does not work well when minutes are in range of 01 - 09
Case 1 : Wrong Output
Declare #Start DateTime='02-03-2014 14:25:00'
Declare #End DateTime='02-03-2014 20:29:46'
Select STR(DateDiff(MINUTE,#Start,#End)/60)+'.'+STR(DateDiff(MINUTE,#Start,#End)%60/0.6)
DateTime Difference : 6.04
Expected Output : 6.10
Actual Output : 6.7
Case 2 : Correct Output
Declare #Start DateTime='02-03-2014 13:55:02'
Declare #End DateTime='02-03-2014 17:33:31'
Select STR(DateDiff(MINUTE,#Start,#End)/60)+'.'+STR(DateDiff(MINUTE,#Start,#End)%60/0.6)
DateTime Difference : 3.38
Expected Output : 6.63
Actual Output : 6.63
what i am missing in case, when minutes are less than 10 ??
DB : SQL Server 2008
60 minutes = 60/60 = 1.0
30 minutes = 30/60 = 0.5
4 minutes = 4/60 = 0.066, not 0.10
0.10 = 6 minutes, not 4 minutes difference as in your first example.
If we temporarily remove the seconds to reduce complexity, then you simply divide the seconds by 3600.00:
Declare #Start DateTime='02-03-2014 14:25:00'
Declare #End DateTime='02-03-2014 20:29:00'
SELECT DATEDIFF(s,#Start,#End)/3600.00
This returns 6.066 which is the correct portion of hours to return 6 hours 4 minutes difference and a far simpler expression.
Try this, it should give a very exact result(after rounding):
Declare #Start DateTime='02-03-2014 13:55:02'
Declare #End DateTime='02-03-2014 17:33:31'
Select round(cast(#end-#start as float)*24, 2)
use this if you want to round down
Select floor(cast(#end-#start as float)*2400) / 100
My friend following is tabular presentation of you requirement.
1 1.666666667
2 3.333333333
3 5
4 6.666666667
5 8.333333333
6 10
7 11.66666667
8 13.33333333
9 15
10 16.66666667
11 18.33333333
12 20
13 21.66666667
14 23.33333333
15 25
16 26.66666667
17 28.33333333
18 30
19 31.66666667
20 33.33333333
21 35
22 36.66666667
23 38.33333333
24 40
25 41.66666667
26 43.33333333
27 45
28 46.66666667
29 48.33333333
30 50
31 51.66666667
32 53.33333333
33 55
34 56.66666667
35 58.33333333
36 60
37 61.66666667
38 63.33333333
39 65
40 66.66666667
41 68.33333333
42 70
43 71.66666667
44 73.33333333
45 75
46 76.66666667
47 78.33333333
48 80
49 81.66666667
50 83.33333333
51 85
52 86.66666667
53 88.33333333
54 90
55 91.66666667
56 93.33333333
57 95
58 96.66666667
59 98.33333333
60 100
In First Case you actual difference is 6 hours & 4 Minutes. So as per requirement ans of 6.07 is correct how you are saying it is wrong?
It seems in STR(DateDiff(MINUTE,#Start,#End)%60/0.6) 0.6 should be replaced with 6.0
The above solution would round off upto 1 place after decimal.
If you want to ROUND off to 2 places after decimal you can try the below snippet:
SELECT CAST(CAST(ROUND(DateDiff(MINUTE,#Start,#End)%60/0.6) AS NUMERIC(12,2)) AS VARCHAR(50))