How to do sum with where clause group by with date? - sql

I want to sum up where clause. I don't know how to show off_duration in the next column.
SELECT CAST([RecordDateTime] AS DATE) AS DATE
,SUM(CAST([units] AS FLOAT)) AS Units
,sum(cast(duration AS INT) / 60) on_duration
FROM [Energies]
WHERE duration_mode = 'ON'
GROUP BY CAST([RecordDateTime] AS DATE)
ORDER BY CAST([RecordDateTime] AS DATE) DESC
op
Datet units on_duration
-------------------------------
2020-01-17 3.53 758
2020-01-16 7.66 973
2020-01-15 15.12 1806
2020-01-13 10.4 500
ex op
date units on_duration off_duration
-----------------------------------------------
2020-01-17 3.53 758 28
2020-01-16 7.66 973 9
2020-01-15 15.12 1806 96
2020-01-13 10.4 500 95
sample data
duration_mode duration RecordDateTime units
-------------------------------------------------------------
ON 187 2020-01-07 20:18:33.9744232 0.19
ON 187 2020-01-07 20:19:03.1554359 0.19
OFF 10 2020-01-07 20:22:13.5283932 0.00
ON 187 2020-01-07 20:24:39.0510166 0.19

I think that you are looking for conditional aggregation:
SELECT
CAST([RecordDateTime] AS DATE) as Date,
SUM(CAST([units] as float)) as Units,
SUM(CASE WHEN duration_mode = 'ON' THEN CAST(duration as int)/60 END) on_duration,
SUM(CASE WHEN duration_mode = 'OFF' THEN CAST(duration as int)/60 END) off_duration
FROM [Energies]
GROUP BY CAST([RecordDateTime] AS DATE)
ORDER BY CAST([RecordDateTime] AS DATE) desc

Related

Cumulative sum by month with missing months

I have to cumulative sum by month a quantity but in some months there's no quantity and SQL does not show these rows.
I have tried multiple other solutions I found here but none of them worked or at least I couldn't get them working. Currently, my code is as follows:
SELECT DISTINCT
A.FromDate
,A.ToDate
,A.OperationType
,A.[ItemCode]
,SUM(A.[Quantity]) OVER (PARTITION BY [ItemCode],OperationType,YEAR ORDER BY MONTH) [Quantity]
FROM (
SELECT
CONVERT(DATE,DATEADD(yy, DATEDIFF(yy, 0, T.OrderDate), 0)) AS FromDate
,EOMONTH(T.OrderDate) ToDate
,DATEPART(MONTH, t.OrderDate) AS [Month]
,DATEPART(YEAR, t.OrderDate) AS [Year]
,SUM(T.[Quantity]) [Quantity]
,OperationType
,[ItemCode]
FROM TEST T
WHERE [ItemCode] != ''
GROUP BY T.OrderDate,[ItemCode],OperationType
) A
With these results:
FromDate
ToDate
OType
ItemCode
Quantity
2021-01-01
2021-01-31
Type1
1
19
2021-01-01
2021-02-28
Type1
1
96
2021-01-01
2021-03-31
Type1
1
116
2021-01-01
2021-04-30
Type1
1
138
2021-01-01
2021-06-30
Type1
1
178
2021-01-01
2021-07-31
Type1
1
203
2021-01-01
2021-08-31
Type1
1
228
2021-01-01
2021-09-30
Type1
1
253
2021-01-01
2021-11-30
Type1
1
330
2021-01-01
2021-12-31
Type1
1
364
2022-01-01
2022-02-28
Type1
1
18
2022-01-01
2022-03-31
Type1
1
42
2022-01-01
2022-04-30
Type1
1
53
And I was expecting these results:
FromDate
ToDate
OType
ItemCode
Quantity
2021-01-01
2021-01-31
Type1
1
19
2021-01-01
2021-02-28
Type1
1
96
2021-01-01
2021-03-31
Type1
1
116
2021-01-01
2021-04-30
Type1
1
138
2021-01-01
2021-05-31
Type1
1
138
2021-01-01
2021-06-30
Type1
1
178
2021-01-01
2021-07-31
Type1
1
203
2021-01-01
2021-08-31
Type1
1
228
2021-01-01
2021-09-30
Type1
1
253
2021-01-01
2021-10-31
Type1
1
253
2021-01-01
2021-11-30
Type1
1
330
2021-01-01
2021-12-31
Type1
1
364
2022-01-01
2022-02-28
Type1
1
18
2022-01-01
2022-03-31
Type1
1
42
2022-01-01
2022-04-30
Type1
1
53
SQL Fiddle link: http://www.sqlfiddle.com/#!18/04a997/1
I would really appreciate some help. Thank you
Here is one way:
WITH m(Earliest,Latest) AS
(
SELECT DATEADD(DAY,1,MIN(EOMONTH(OrderDate,-1))),
MAX(EOMONTH(OrderDate)) FROM dbo.TEST
), TypeCodes AS
(
SELECT DISTINCT ItemCode, OperationType
FROM dbo.TEST
), Months AS
(
SELECT Month = DATEADD(MONTH, ROW_NUMBER()
OVER (ORDER BY ##SPID)-1, Earliest)
FROM m CROSS APPLY STRING_SPLIT(REPLICATE(',',
DATEDIFF(MONTH,Earliest,Latest)),',')
), raw AS
(
SELECT m.Month, i.OperationType, i.ItemCode,
Q = COALESCE(SUM(Quantity),0)
FROM Months AS m
CROSS JOIN TypeCodes AS i
LEFT OUTER JOIN dbo.TEST AS t
ON t.OrderDate >= m.Month
AND t.OrderDate < DATEADD(MONTH, 1, m.Month)
AND i.ItemCode = t.ItemCode
AND i.OperationType = t.OperationType
GROUP BY m.Month, i.OperationType, i.ItemCode
)
SELECT FromDate = Month,
ToDate = EOMONTH(Month),
OperationType,
ItemCode,
Quantity = SUM(Q) OVER (ORDER BY Month)
FROM raw;
Working example in this fiddle.
If you can't use STRING_SPLIT() because your database is stuck on an older compatibility level, you could put this function in a database that isn't:
USE ModernDatabase;
GO
CREATE FUNCTION dbo.StringSplit(#list nvarchar(max), #delim nchar(1))
RETURNS TABLE
AS
RETURN (SELECT value FROM STRING_SPLIT(#list, #delim));
Then you change:
FROM m CROSS APPLY STRING_SPLIT(...
To:
FROM m CROSS APPLY ModernDatabase.dbo.StringSplit(...

Finding most recent startdate, and endDate from consecutive dates

I have a table like below:
user_id
store_id
stock
date
116
2
0
2021-10-18
116
2
0
2021-10-19
116
2
0
2021-10-20
116
2
0
2021-08-16
116
2
0
2021-08-15
116
2
0
2021-07-04
116
2
0
,2021-07-03
389
2
0
2021-07-02
389
2
0
2021-07-01
389
2
0
2021-10-27
52
6
0
2021-10-28
52
6
0
2021-10-29
52
6
0
2021-10-30
116
38
0
2021-05-02
116
38
0
2021-05-03
116
38
0
2021-05-04
116
38
0
2021-04-06
The table can have multiple consecutive days where a product ran out of stock, so I'd like to create a query with the last startDate and endDate where the product ran out of stock. For the table above, the results have to be:
user_Id
store_id
startDate
endDate
116
2
2021-10-18
2021-10-20
116
38
2021-05-02
2021-05-04
389
2
2021-07-01
2021-07-02
52
6
2021-10-28
2021-10-30
I have tried the solution with row_number(), but it didn't work. Does someone have a tip or idea to solve this problem with SQL (PostgreSQL)?
here is how you can do it :
select user_id, store_id,min(date) startdate,max(date) enddate
from (
select *, rank() over (partition by user_id, store_id order by grp desc) rn from (
select *, date - row_number() over (partition by user_id,store_id order by date) * interval '1 day' grp
from tablename
) t) t where rn = 1
group by user_id, store_id,grp
db<>fiddle here

First and last record of a date in SQL Server

I want to generate a user login report where I want to show the users first login time and last logout time for each day of a month. The table of UserLoginSession is as below
UserLoginSessionId
UserId
LoginDate
LogoutDate
1310582
59
2021-04-30 15:49:54.997
2021-04-30 17:31:18.833
1310579
59
2021-04-30 14:53:51.460
NULL
1310575
59
2021-04-30 14:39:45.937
2021-04-30 14:52:23.150
1310569
59
2021-04-30 13:49:36.137
NULL
1300484
59
2021-04-28 15:17:48.837
NULL
1300478
59
2021-04-28 12:17:50.200
NULL
1300466
59
2021-04-28 04:23:48.697
2021-04-28 07:45:11.937
1299527
2466
2021-04-18 06:07:51.070
NULL
1299489
2466
2021-04-17 06:57:01.860
2021-04-17 06:57:28.260
1299449
2466
2021-04-16 10:16:54.730
NULL
1299442
2466
2021-04-16 10:08:30.187
2021-04-16 10:36:05.963
1299422
2466
2021-04-16 07:30:32.990
2021-04-16 10:15:25.777
The output report should be like below where if the logout date is null, it should take the end time of the day
UserId
LoginDate
LogoutDate
59
2021-04-30 13:49:36.137
2021-04-30 17:31:18.833
59
2021-04-28 04:23:48.697
2021-04-28 23:59:59.000
2466
2021-04-18 06:07:51.070
2021-04-18 23:59:59.000
2466
2021-04-17 06:57:01.860
2021-04-17 06:57:28.260
2466
2021-04-16 07:30:32.990
2021-04-16 23:59:59.000
I have tried the below query but it is giving me output in separate rows.
select UserId, case when rn1 = 1 then LoginDate end as [LoginDate], case when rn2 = 1 then LogoutDate end as [LogoutDate]
from (
select
row_number() over (partition by U.UserId, convert(date,s.LoginDate) order by s.LoginDate) as rn1,
row_number() over (partition by U.UserId, convert(date,s.LogoutDate) order by s.LogoutDate desc) as rn2,
S.*
from UserLoginSession S
where S.CreatedAt between #StartDate and #EndDate
) as SubQueryTable
where rn1 = 1 or rn2 = 1
I am not able to bring both the records in a single row in the query. How can I modify my query to achieve the desired result?
Using MIN and MAX and hacking around when LogoutDate is NULL:
SELECT UserId, CONVERT(date, LoginDate), MIN(LoginDate), ISNULL(MAX(LogoutDate), DATEADD(MS, -2, CONVERT(DATETIME,DATEADD(D, 1, CONVERT(date, LoginDate)))))
FROM UserLoginSession
GROUP BY UserId,CONVERT(date, LoginDate)
ORDER BY UserId,CONVERT(date, LoginDate)

Selecting first element in Group by object Postgres

I have the following table and I want to get the specidic Amount per loan_ID that corresponds to the earliest observation with greater than or equal to 10 dpd per month.
Loan_ID date dpd Amount
1 1/1/2017 1 55
1 1/2/2017 2 100
1 1/3/2017 3 5000
1 1/4/2017 5 6000
1 1/5/2017 10 50000
1 1/6/2017 15 50001
1 1/9/2017 31 50004
1 1/10/2017 55 50005
1 1/11/2017 59 50006
1 1/12/2017 65 50007
1 1/13/2017 70 80000
1 1/20/2017 85 900000
1 1/29/2017 92 100000
1 1/30/2017 93 10000
2 1/1/2017 0 522
2 1/2/2017 8 5444
2 1/3/2017 12 8784
2 1/6/2017 15 6221
2 1/12/2017 18 2220
2 1/13/2017 20 177
2 1/29/2017 35 5151
2 1/30/2017 60 40000
2 1/31/2017 61 5500
The expected output:
Loan_ID Month Amount
1 1 50000
2 1 8784
SELECT DISTINCT ON ("Loan_ID", date_trunc('month', "date"))
"Loan_ID",
date_trunc('month', "date")::date as month,
"Amount"
FROM
loans
WHERE
dpd >= 10
ORDER BY
"Loan_ID",
date_trunc('month', "date"),
"date"
;
Returns:
Loan_ID
month
Amount
1
2017-01-01
50000
2
2017-01-01
8784
You can find test case in db<>fiddle
Hmmm . . . if you want the amount per month and the first date that matches the condition, then you want conditional aggregation:
select loan_id, date_trunc('month', date) as mon,
sum(dpd),
min(case when dpd >= 10 then dpd end) as first_dpd_10
from t
group by load_id, mon;
Edit: Based on your comment, you can use distinct on:
select distinct on (loan_id, date_trunc('month', date)) t.*
min(case when dpd >= 10 then dpd end) as first_dpd_10
from t
where dpd >= 10
order by load_id, date_trunc('month', date), date

SQL : GROUP and MAX multiple columns

I am a SQL beginner, can anyone please help me about a SQL query?
my table looks like below
PatientID Date Time Temperature
1 1/10/2020 9:15 36.2
1 1/10/2020 20:00 36.5
1 2/10/2020 8:15 36.1
1 2/10/2020 18:20 36.3
2 1/10/2020 9:15 36.7
2 1/10/2020 20:00 37.5
2 2/10/2020 8:15 37.1
2 2/10/2020 18:20 37.6
3 1/10/2020 8:15 36.2
3 2/10/2020 18:20 36.3
How can I get each patient everyday's max temperature:
PatientID Date Temperature
1 1/10/2020 36.5
1 2/10/2020 36.3
2 1/10/2020 37.5
2 2/10/2020 37.6
Thanks in advance!
For this dataset, simple aggregation seems sufficient:
select patientid, date, max(temperature) temperature
from mytable
group by patientid, date
On the other hand, if there are other columns that you want to display on the row that has the maximum daily temperature, then it is different. You need some filtering; one option uses window functions:
select *
from (
select t.*,
rank() over(partition by patientid, date order by temperature desc)
from mytable t
) t
where rn = 1