Adding column which groups data by time - sql-server

I've got a table which shows: Power, Time, Diff-Days, Diff-Hours, Diff-Minutes where the diff columns use datediff and lag to calculate the difference in times between the rows.
(PowerkW) (Time) (Diff-Days) (Diff-Hours) (Diff-Minutes)
31011.39 2014-01-01 00:30:00 NULL NULL NULL
31838.74 2014-01-01 00:40:00 0 0 -10
32356.35 2014-01-01 00:50:00 0 0 -10
32358.82 2014-01-01 01:00:00 0 -1 -10
32414.15 2014-01-01 01:10:00 0 0 -10
32413.81 2014-01-01 01:20:00 0 0 -10
32412.35 2014-01-01 01:30:00 0 0 -10
32416.23 2014-01-01 01:40:00 0 0 -10
32014.94 2014-01-01 01:50:00 0 0 -10
31184.45 2014-01-01 03:40:00 0 -2 -110
32403.38 2014-01-01 03:50:00 0 0 -10
32415.07 2014-01-01 04:00:00 0 -1 -10
32388.04 2014-01-01 04:10:00 0 0 -10
32320.70 2014-01-01 04:20:00 0 0 -10
32297.44 2014-01-01 04:30:00 0 0 -10
What I want is a 6th column which groups these rows into events which are happening consecutively, i.e 9 happening every 1 minutes one after the other would have 1 in the 6th column then there could be a 2 hour difference and then 6 rows happening after each other which could have 2 in the 6th column, is this possible?
i.e.
(PowerkW) (Time) (Diff-Days) (Diff-Hours) (Diff-Minutes) (Group)
31011.39 2014-01-01 00:30:00 NULL NULL NULL 1
31838.74 2014-01-01 00:40:00 0 0 -10 1
32356.35 2014-01-01 00:50:00 0 0 -10 1
32358.82 2014-01-01 01:00:00 0 -1 -10 1
32414.15 2014-01-01 01:10:00 0 0 -10 1
32413.81 2014-01-01 01:20:00 0 0 -10 1
32412.35 2014-01-01 01:30:00 0 0 -10 1
32416.23 2014-01-01 01:40:00 0 0 -10 1
32014.94 2014-01-01 01:50:00 0 0 -10 1
31184.45 2014-01-01 03:40:00 0 -2 -110 2
32403.38 2014-01-01 03:50:00 0 0 -10 2
32415.07 2014-01-01 04:00:00 0 -1 -10 2
32388.04 2014-01-01 04:10:00 0 0 -10 2
32320.70 2014-01-01 04:20:00 0 0 -10 2
32297.44 2014-01-01 04:30:00 0 0 -10 2

If your definition of consecutive is based on the "diff minutes" being greater than some value (or less than, given that these are negative), then you can use a cumulative sum:
with q as (<your query here>)
select q.*,
sum(case when diff_minutes < -50 then 1 else 0 end) over (order by time) as grp
from q;
If you really want to start at "1", then just add one to the value.

Related

Combine a column while grouping on another column with similar values

I have been working on a SQL Server stored procedure to find a solution illustrated in the results table below. I am close in my solution however I get multiple results on a column I would like to have grouped altogether.
DECLARE #fiscal_year AS INT
SET #fiscal_year = '2016'
SELECT
[ActionDate] AS [PPDate],
SUM([GAL].[GCount]) AS [GCount],
SUM([GAL].[LCount]) AS [LCount],
CONCAT(SUM([GAL].[GCount]), ' Gain(s): (', [GAL].[GComments], '); ', SUM([GAL].
[LCount]), ' Loss(es): (', [GAL].[LComments], ')') AS [Details]
FROM
[dbo].[TableA] [GAL]
GROUP BY
[GAL].[ActionDate], [GAL].[GainComments], [Gal].[LossComments]
I have a table as follows.
Table A:
ID ActionDate GCount GainRID GComments LCount LossRID LComments
1 2013-06-04 1 35 John 0 -1 NULL
2 2013-06-04 2 35 M & R 0 -1 NULL
3 2014-01-10 1 60 Paul 0 -1 NULL
4 2014-01-10 1 60 Mona 0 -1 NULL
5 2013-10-05 3 58 Tim 0 -1 NULL
6 2013-10-05 2 58 Ruby 0 -1 NULL
7 2013-10-05 0 -1 NULL 2 50 Jude & Mo
8 2013-10-05 0 -1 NULL 1 50 Frank
9 2013-10-05 0 -1 NULL 1 50 Linda
10 2014-01-10 0 -1 NULL 1 70 Eliz
11 2014-01-10 0 -1 NULL 1 70 Georgina
12 2014-01-10 0 -1 NULL 1 70 Christina
13 2013-10-05 0 -1 NULL 2 64 Joan & Mike
14 2013-10-05 0 -1 NULL 1 64 Mitch
...and I would like to have it grouped by Action Date, using the SUM() function on the GainCount and LossCount fields. The Details field is combined by
GainReasonID, LossReasonID, Gain and Loss Comments such that the table ends up like this.
Results
PPDate GCount LCount Details
2013-06-04 2 0 "(2) Gains: 2(35) -- John, M & R
(0) Losses: "
2013-10-05 2 3 "(2) Gains: 2(58) -- Tim, Ruby
(3) Losses: 3(50) -- Jude & Mo, Frank, Linda ,
2(64) -- Joan & Mike, Mitch"
2014-01-10 2 3 "(2) Gains: 2(60) -- Paul, Mona
(3) Losses: 3(70) -- Eliz, Georgina, Christina"

Use Sum on extra aggregation and Make Total

I want to create an indexed View.
I have this query:
SELECT srvmn.BBC_ID AS Inventory,
srvInv.ObjectID,
srv.State,
SUM( IIF(srvInv.Direction = srvInv.ReverseBroken, 1, 0)) AS Broken,
SUM(IIF(srvInv.Direction = 0, 1, -1)) AS Sum,
COUNT_BIG(*) AS CountLines
FROM table1 srvmn
JOIN table2 srv
ON srv.ServiceManID = srvmn.ID
JOIN table3 srvInv
ON srv.ID = srvInv.ServiceID
WHERE srv.State > 321
AND srv.State <> 123
GROUP BY srvInv.ObjectID,
srv.State,
srvInv.Direction,
srvInv.ReverseBroken,
srvmn.BBC_ID
ORDER BY srvInv.ObjectID
So, the Sum is not working properly also I fix it with this approach:
SELECT A.Inventory,
A.ObjectID,
A.State,
A.Broken,
SUM(A.Sum) AS Sum
FROM
(
SELECT srvmn.BBC_ID AS Inventory,
srvInv.ObjectID,
srv.State,
IIF(srvInv.Direction = srvInv.ReverseBroken, 1, 0) AS Broken,
SUM(IIF(srvInv.Direction = 0, 1, -1)) AS Sum,
COUNT_BIG(*) AS CountLines
FROM table1 srvmn
JOIN table2 srv
ON srv.ServiceManID = srvmn.ID
JOIN table3 srvInv
ON srv.ID = srvInv.ServiceID
WHERE srv.State > 321
AND srv.State <> 123
GROUP BY srvInv.ObjectID,
srv.State,
srvInv.Direction,
srvInv.ReverseBroken,
srvmn.BBC_ID
) AS A
GROUP BY A.Inventory,
A.ObjectID,
A.State,
A.Broken;
Result is OK, but Derived Tables are not allowed in Indexed Views.
I try to using "Over Partition" in Sum, but the result is not OK.
How I can fix this issue?
Correct Result :
Inventory ObjectID State Broken Sum
------------------------------------------------
NULL 2 500 0 -1
NULL 3 320 1 1
NULL 3 500 0 2
NULL 3 600 0 1
NULL 18 600 0 -1
NULL 20 600 0 -1
1162 20 600 0 1
NULL 24 600 0 1
NULL 26 310 0 -3
NULL 26 320 0 -1
NULL 26 600 0 7
442 26 500 0 8
442 26 500 1 1
442 26 600 0 -5
1162 26 600 0 0
NULL 27 500 0 4
NULL 27 600 0 2
1162 27 600 0 1
1162 28 600 0 3
Not Ok Result:
Inventory ObjectID State Broken Sum CountLines
-------------------------------------------------------------
NULL 2 500 0 -1 1
NULL 3 500 0 2 2
NULL 3 600 0 1 1
NULL 18 600 0 -1 1
1162 20 600 0 3 3
1162 20 600 0 -2 2
NULL 20 600 0 1 1
NULL 20 600 0 -2 2
NULL 24 600 0 -1 1
NULL 24 600 0 2 2
442 26 600 0 -7 7
NULL 26 600 0 -18 18
1162 26 600 0 1 1
NULL 26 600 0 25 25
442 26 500 1 1 1
442 26 600 0 2 2
1162 26 600 0 -1 1
442 26 500 0 8 8
NULL 27 600 0 -3 3
1162 27 600 0 1 1
Please try it :
SELECT
srvmn.BBC_ID AS Inventory,
srvInv.ObjectID,
srv.State,
SUM(IIF(srvInv.Direction = srvInv.ReverseBroken, 1, 0)) AS Broken,
SUM(IIF(srvInv.Direction = 0, 1, -1)) AS Sum
FROM table1 srvmn
JOIN table2 srv ON srv.ServiceManID = srvmn.ID
JOIN table3 srvInv ON srv.ID = srvInv.ServiceID
WHERE srv.State > 321 AND srv.State <> 123
GROUP BY
srvInv.ObjectID,
srv.State,
srvInv.ReverseBroken,
srvmn.BBC_ID
You should not use Field "srvInv.Direction" in "Group By"

SQL Pivot Table - Subqueries

I have a program that is logging the time a user spends on certain aspects, some are identified as specific "time". I'm struggling to get multiple lines of Grouped query results into a single line for each month as a "summary".
My current query:
SELECT
TotalMins = SUM(Minutes)
,DateMonth = MONTH(Date)
,ID1
,PC
FROM User_Time_Log
WHERE
(UserID = 1)
AND (YEAR(Date) = 2018)
GROUP BY
MONTH(Date)
,ID1
,PC1
Current results:
TotalMins DateMonth ID1 PC1
192 1 0 0
306 1 0 100
113 2 0 0
365 2 0 100
14 2 1 0
3 2 1 100
75 3 0 0
253 3 0 100
3 3 1 0
300 4 0 0
233 4 0 100
10 4 1 0
23 4 1 100
438 5 0 0
134 5 0 100
19 5 1 0
49 5 1 100
0 9 1 0
11 10 0 0
21 10 0 60
167 10 1 100
What I would like to do from this point is to create a table showing all 12 months, regardless of whether there is information within that month or not, and show the relative information within each row for that month. for example:
DateMonth NonID1 TimeID1 TimePC1 (Round((PC1/100)*TotalMins)) TimePC1ID1
1 192 0 306 0
2 113 14 365 3
3 75 3 253 0
4 300 10 233 23
5 438 19 134 49
6 0 0 0 0
7 0 0 0 0
8 0 0 0 0
9 0 0 0 0
10 11 0 13 167
11 0 0 0 0
12 0 0 0 0
What's the most efficient way to do this?
Note: I have also created a table to give me 1-12 as rows that I can use to give me the months that I need to use, where information is not within the user_time_log.
Here's a simple way to do what you're looking for:
First, create your table of month values. I made a simple temp table with a single column.
CREATE TABLE #Dates (MonthNum INT)
INSERT INTO #Dates
(
MonthNum
)
VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
Next, you can put your existing query into a CTE, then LEFT JOIN to your table of months. You'll want to put your columns into a SUM'd CASE statement, like so:
;WITH Aggregation AS
(
SELECT
TotalMins = SUM(Minutes)
,DateMonth = MONTH(Date)
,ID1
,PC1
FROM #User_Time_Log
WHERE
(UserID = 1)
AND (YEAR(Date) = 2018)
GROUP BY
MONTH(Date)
,ID1
,PC1
)
SELECT
d.MonthNum
,NonID1 = SUM(CASE WHEN ID1 = 0 THEN TotalMins ELSE 0 END)
,TimeID1 = SUM(CASE WHEN ID1 = 1 THEN TotalMins ELSE 0 END)
,TimePC1 = SUM(CASE WHEN ID1 = 0 THEN ROUND((PC1/100)*TotalMins,0) ELSE 0 END)
,TimePC1ID1 = SUM(CASE WHEN ID1 = 1 THEN ROUND((PC1/100)*TotalMins,0) ELSE 0 END)
FROM #Dates d
LEFT JOIN Aggregation a ON d.MonthNum = a.DateMonth
GROUP BY d.MonthNum
Output would then look like this:
MonthNum NonID1 TimeID1 TimePC1 TimePC1ID1
1 498 0 306 0
2 478 17 365 3
3 328 3 253 0
4 533 33 233 23
5 572 68 134 49
6 0 0 0 0
7 0 0 0 0
8 0 0 0 0
9 0 0 0 0
10 32 167 0 167
11 0 0 0 0
12 0 0 0 0
EDIT:
The ROUND() function call can be changed slightly to accomodate your need for decimal results. The first parameter of ROUND() is the expression you want to round, and the second is the number of decimal places to round to. Positive numbers indicate the number of places to the right of the decimal to round to. Negative numbers indicate the number of places to the left of the decimal to round to. So if you set it to 2, you'll get an answer rounded to the nearest hundredth.
But there's one more tweak we need. PC1 and TotalMins are both assumed to be INTs in my answer. So we have to give the SQL engine a little help so that it calculates the answer as a DECIMAL. By CAST()ing the INTs to DECIMALs, SQL will perform the arithmetic op as decimal math instead of integer math. You'd just have to change TimePC1 and TimePC1ID1 like so:
,TimePC1 = SUM(CASE WHEN ID1 = 0 THEN ROUND((CAST(PC1 AS DECIMAL)/100)*CAST(TotalMins AS DECIMAL),2) ELSE 0 END)
,TimePC1ID1 = SUM(CASE WHEN ID1 = 1 THEN ROUND((CAST(PC1 AS DECIMAL)/100)*CAST(TotalMins AS DECIMAL),2) ELSE 0 END)
Then the output looks like this:
MonthNum NonID1 TimeID1 TimePC1 TimePC1ID1
1 498 0 306.000000 0.000000
2 478 17 365.000000 3.000000
3 328 3 253.000000 0.000000
4 533 33 233.000000 23.000000
5 572 68 134.000000 49.000000
6 0 0 0.000000 0.000000
7 0 0 0.000000 0.000000
8 0 0 0.000000 0.000000
9 0 0 0.000000 0.000000
10 32 167 12.600000 167.000000
11 0 0 0.000000 0.000000
12 0 0 0.000000 0.000000

Need help to get sql query output like this

This is my query
select
dtfromdate, dttodate,
(SELECT DATEDIFF(day, dtfromdate, dtTodate)) AS NumberOfDays,
fltspl
from dbo.tblHR_SpecialLeaveTransaction
where
nvrempcode = 'MCL1218' and nvrstatus = 1
order by
dtfromdate
Result :
dtfromdate dttodate NumberOfDays fltspl
----------------------- ----------------------- ------------ ----------------------
2012-05-01 00:00:00 2012-05-31 00:00:00 30 30
Another query
select
dtfromdate, dtTodate,
(SELECT DATEDIFF(day, dtfromdate, dtTodate) ) AS NumberOfDays,
fltcl, fltsl, fltpl, fltcompoff, fltod, fltlop,
isnull(fltflexiL, 0) as fltflexiL
from
tblhr_leavetransaction
where
nvrempcode = 'MCL1218' and nvrstatus = 1
order by
dtfromdate
Result:
dtfromdate dtTodate NumberOfDays fltcl fltsl fltpl fltcompoff fltod fltlop fltflexiL
----------------------- ----------------------- ------------ ---------------------- ---------------------- ---------------------- ---------------------- ---------------------- ---------------------- ----------------------
2011-01-14 00:00:00 2011-01-14 00:00:00 0 1 0 0 0 0 0 0
2011-01-17 00:00:00 2011-01-17 00:00:00 0 1 0 0 0 0 0 0
2011-01-25 00:00:00 2011-01-25 00:00:00 0 0 0 0 0 1 0 0
2011-04-01 00:00:00 2011-04-02 00:00:00 1 0 0 0 0 2 0 0
2011-05-14 00:00:00 2011-05-14 00:00:00 0 0 0 0 0 1 0 0
2011-05-16 00:00:00 2011-05-16 00:00:00 0 0 0 0 1 0 0 0
2011-05-18 00:00:00 2011-05-18 00:00:00 0 1 0 0 0 0 0 0
2011-05-19 00:00:00 2011-05-20 00:00:00 1 0 2 0 0 0 0 0
2011-05-21 00:00:00 2011-05-21 00:00:00 0 1 0 0 0 0 0 0
2011-05-23 00:00:00 2011-05-23 00:00:00 0 0 0 0 1 0 0 0
I need the output like this,
dtfromdate dtTodate NumberOfDays fltcl fltsl fltpl fltcompoff fltod fltlop fltflexiL fltspl
----------------------- ----------------------- ------------ ---------------------- ---------------------- ---------------------- ---------------------- ---------------------- ---------------------- ---------------------- ----------
2011-01-14 00:00:00 2011-01-14 00:00:00 0 1 0 0 0 0 0 0 0
2011-01-17 00:00:00 2011-01-17 00:00:00 0 1 0 0 0 0 0 0 0
2011-01-25 00:00:00 2011-01-25 00:00:00 0 0 0 0 0 1 0 0 0
2011-04-01 00:00:00 2011-04-02 00:00:00 1 0 0 0 0 2 0 0 0
2011-05-14 00:00:00 2011-05-14 00:00:00 0 0 0 0 0 1 0 0 0
2011-05-16 00:00:00 2011-05-16 00:00:00 0 0 0 0 1 0 0 0 0
2011-05-18 00:00:00 2011-05-18 00:00:00 0 1 0 0 0 0 0 0 0
2011-05-19 00:00:00 2011-05-20 00:00:00 1 0 2 0 0 0 0 0 0
2011-05-21 00:00:00 2011-05-21 00:00:00 0 1 0 0 0 0 0 0 0
2011-05-23 00:00:00 2011-05-23 00:00:00 0 0 0 0 1 0 0 0 0
2012-05-01 00:00:00 2012-05-31 00:00:00 30 0 0 0 0 0 0 0 30
Looks like you just want to union two queries together. To do this both queries must include all columns, just set those to null/zero as necessary. One other slight difficulty is that you cant use order by when unioning, unless you subselect the whole thing.
Without the order by:
select
dtfromdate, dttodate,
(SELECT DATEDIFF(day, dtfromdate, dtTodate)) AS NumberOfDays,
0 as fltcl,
0 as fltsl,
0 as fltpl,
0 as fltcompoff,
0 as fltod,
0 as fltlop,
0 as fltflexiL,
fltspl
from dbo.tblHR_SpecialLeaveTransaction
where
nvrempcode = 'MCL1218' and nvrstatus = 1
union
select
dtfromdate, dtTodate,
(SELECT DATEDIFF(day, dtfromdate, dtTodate) ) AS NumberOfDays,
fltcl, fltsl, fltpl, fltcompoff, fltod, fltlop,
isnull(fltflexiL, 0) as fltflexiL ,
0 as fltspl
from
tblhr_leavetransaction
where
nvrempcode = 'MCL1218' and nvrstatus = 1
If you need a specific order:
SELECT * FROM
(
select
dtfromdate, dttodate,
(SELECT DATEDIFF(day, dtfromdate, dtTodate)) AS NumberOfDays,
0 as fltcl,
0 as fltsl,
0 as fltpl,
0 as fltcompoff,
0 as fltod,
0 as fltlop,
0 as fltflexiL,
fltspl
from dbo.tblHR_SpecialLeaveTransaction
where
nvrempcode = 'MCL1218' and nvrstatus = 1
union
select
dtfromdate, dtTodate,
(SELECT DATEDIFF(day, dtfromdate, dtTodate) ) AS NumberOfDays,
fltcl, fltsl, fltpl, fltcompoff, fltod, fltlop,
isnull(fltflexiL, 0) as fltflexiL ,
0 as fltspl
from
tblhr_leavetransaction
where
nvrempcode = 'MCL1218' and nvrstatus = 1
) src
order by dtfromdate

SQL Query multiple values of a column as multiple columns (SQL 2005)

When I run a SQL query on a single table and here is the data (this is just a sample, error column might be more than 10)
time total Error
00:16 6 10000(E)
00:20 4 10000(E)
00:46 2 10000(E)
01:01 2 10000(E)
01:40 2 10000(E)
02:07 2 10000(E)
02:52 1 10000(E)
04:27 2 10000(E)
04:29 6 10000(E)
04:32 4 10000(E)
04:49 2 10000(E)
04:50 2 10000(E)
06:18 2 10000(E)
09:04 1 10000(E)
10:57 4 10000(E)
10:58 4 10000(E)
00:36 1 9401(E)
00:37 1 9401(E)
00:57 1 9401(E)
00:58 1 9401(E)
01:32 1 9401(E)
01:33 1 9401(E)
02:36 2 9401(E)
03:05 1 9401(E)
03:06 1 9401(E)
09:53 2 9401(E)
12:11 2 9401(E)
12:12 4 9401(E)
12:41 1 9401(E)
I want to write a SQL query so that I want to get the above data like this
time 10000(E) 9401(E)
---------------------------
00:16 6 0
00:20 4 0
00:36 0 1
00:37 0 1
00:46 2 0
00:57 0 1
00:58 0 1
01:01 2 0
01:32 0 1
01:33 0 1
01:40 2 0
02:07 2 0
02:36 0 2
02:52 1 0
03:05 0 1
03:06 0 1
04:27 2 0
04:29 6 0
04:32 4 0
04:49 2 0
04:50 2 0
06:18 2 0
09:04 1 0
09:53 0 1
10:57 4 0
10:58 4 0
12:11 0 2
12:12 0 4
12:41 0 1
is this possible??
Does this meet your requirement?
select e.time
, e.[10000(E)]
, e.[9401(E)]
from (
select time
, SUM(case when Error LIKE N'10000(E)' then Total else NULL end) as [10000(E)]
, null as [9401(E)]
from MyTable
where Error LIKE N'10000(E)'
group by time
union
select time
, null as [10000(E)]
, SUM(case when Error LIKE N'9401' then Total else NULL end) as [9401(E)]
from MyTable
where Error LIKE N'9401(E)'
group by time
) e
order by e.time
If no, please tell me about the result so that I can bring the righteous corrections.
The SUM function only comes to group the number of occurences of a same error into one given time, which seems to be what you have in your table, actually. So, it shouldn't modify any data. On the other hand, if you had two different records of the same error by the same time, then they should be grouped by this time and the total of occurences of this error will be additioned.
For your given in- and output it could be as simple as this.
SELECT *
FROM (
SELECT time
, [10000(E)] = Total
, [9401(E)] = 0
FROM YourTable
WHERE Error = '10000(E)'
UNION ALL
SELECT time
, [10000(E)] = 0
, [9401(E)] = Total
FROM YourTable
WHERE Error = '9401(E)'
) q
ORDER BY
time

Resources