I have Two table [FuelTankHistory] and [Product]
CREATE TABLE [dbo].[FuelTankHistory](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[FuelLevel] [decimal](18, 2) NULL,
[FuelLevelTime] [datetime] NULL,
[TankId] [bigint] NULL,
[Volume] [decimal](18, 2) NULL,
[ProductId] [bigint] NOT NULL
)
GO
CREATE TABLE [dbo].[Product](
[ProductId] [bigint] IDENTITY(1,1) NOT NULL,
[ProductName] [varchar](50) NULL,
[IsActive] [bit] NULL)
GO
click here to view on SQL Fiddle. Now I want to Generate a report Like Below (sale report for petrol)
ReportDate sale_petrol
2021-08-01 113.000
2021-08-02 348.000
2021-08-03 -134.000
2021-08-04 519.000
2021-08-05 0.000
I my case tank 1 and 2 are petrol tanks, now the tricky thing is I need to get sale of petrol between some date range.
if the date is '2021-08-02'
I want to get
first level between '2021-08-01 13:00:00' and '2021-08-02 13:00:00' (opening_stock of 24 hour)
and
last level between '2021-08-01 13:00:00' and '2021-08-02 13:00:00' (closing_stock of 24 hour)
for every tank, then get total sale done from every tank which is (opening_stock - closing_stock). then get SUM of all tanks (in my case petrol tanks), in my case which is equal to 348.000 !
I have created a query to do this. but its taking too long to generate report for a month because history table have millions of records and I don't think looping is a good way to do this.
If you are facing any problem to understand my problem, please visit SQL Fiddle by clicking the given link
Schema and data
CREATE TABLE [dbo].[FuelTankHistory](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[FuelLevel] [decimal](18, 2) NULL,
[FuelLevelTime] [datetime] NULL,
[TankId] [bigint] NULL,
[Volume] [decimal](18, 2) NULL,
[ProductId] [bigint] NOT NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Product](
[ProductId] [bigint] IDENTITY(1,1) NOT NULL,
[ProductName] [varchar](50) NULL,
[IsActive] [bit] NULL)
GO
SET IDENTITY_INSERT [dbo].[FuelTankHistory] ON
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (1, CAST(124.00 AS Decimal(18, 2)), CAST(N'2021-08-01T01:05:12.000' AS DateTime), 1, CAST(120.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (2, CAST(665.00 AS Decimal(18, 2)), CAST(N'2021-08-01T12:05:12.000' AS DateTime), 2, CAST(333.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (3, CAST(879.00 AS Decimal(18, 2)), CAST(N'2021-08-01T07:05:12.000' AS DateTime), 2, CAST(345.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (4, CAST(675.00 AS Decimal(18, 2)), CAST(N'2021-08-01T18:05:12.000' AS DateTime), 2, CAST(567.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (5, CAST(434.00 AS Decimal(18, 2)), CAST(N'2021-08-01T20:05:12.000' AS DateTime), 2, CAST(744.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (6, CAST(552.00 AS Decimal(18, 2)), CAST(N'2021-08-01T05:05:12.000' AS DateTime), 2, CAST(346.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (7, CAST(835.00 AS Decimal(18, 2)), CAST(N'2021-08-02T08:05:12.000' AS DateTime), 1, CAST(643.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (8, CAST(246.00 AS Decimal(18, 2)), CAST(N'2021-08-02T04:05:12.000' AS DateTime), 1, CAST(897.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (9, CAST(477.00 AS Decimal(18, 2)), CAST(N'2021-08-02T13:05:12.000' AS DateTime), 2, CAST(675.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (10, CAST(235.00 AS Decimal(18, 2)), CAST(N'2021-08-03T23:05:12.000' AS DateTime), 1, CAST(67.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (11, CAST(88.00 AS Decimal(18, 2)), CAST(N'2021-08-03T19:05:12.000' AS DateTime), 2, CAST(87.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (12, CAST(345.00 AS Decimal(18, 2)), CAST(N'2021-08-03T02:05:12.000' AS DateTime), 1, CAST(67.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (13, CAST(255.00 AS Decimal(18, 2)), CAST(N'2021-08-03T07:05:12.000' AS DateTime), 2, CAST(65.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (14, CAST(433.00 AS Decimal(18, 2)), CAST(N'2021-08-03T04:05:12.000' AS DateTime), 1, CAST(345.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (15, CAST(567.00 AS Decimal(18, 2)), CAST(N'2021-08-03T17:05:12.000' AS DateTime), 2, CAST(565.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (16, CAST(388.00 AS Decimal(18, 2)), CAST(N'2021-08-04T22:05:12.000' AS DateTime), 1, CAST(45.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (17, CAST(234.00 AS Decimal(18, 2)), CAST(N'2021-08-04T06:05:12.000' AS DateTime), 1, CAST(34.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (18, CAST(976.00 AS Decimal(18, 2)), CAST(N'2021-08-04T09:05:12.000' AS DateTime), 1, CAST(124.00 AS Decimal(18, 2)), 1)
GO
INSERT [dbo].[FuelTankHistory] ([Id], [FuelLevel], [FuelLevelTime], [TankId], [Volume], [ProductId]) VALUES (19, CAST(345.00 AS Decimal(18, 2)), CAST(N'2021-08-04T11:05:12.000' AS DateTime), 2, CAST(45.00 AS Decimal(18, 2)), 1)
GO
SET IDENTITY_INSERT [dbo].[FuelTankHistory] OFF
GO
SET IDENTITY_INSERT [dbo].[Product] ON
GO
INSERT [dbo].[Product] ([ProductId], [ProductName], [IsActive]) VALUES (1, N'Petrol', 1)
GO
INSERT [dbo].[Product] ([ProductId], [ProductName], [IsActive]) VALUES (2, N'Diesel', 1)
GO
INSERT [dbo].[Product] ([ProductId], [ProductName], [IsActive]) VALUES (3, N'CNG', 1)
GO
SET IDENTITY_INSERT [dbo].[Product] OFF
GO
My Query to generate Report
declare @dt1 date='2021-08-01'
declare @dt2 date='2021-08-22'
DECLARE @tbl_temp_max TABLE(max_fuelLevel decimal(18,3),FuelStationTankId bigint,ReportDate date)
DECLARE @tbl_temp_min TABLE(min_fuelLevel decimal(18,3),FuelStationTankId bigint,ReportDate date)
-- is there any way to get both max and min in single query?
-- and do the same thing without using loop
WHILE ( @dt1 <= @dt2)
BEGIN
-- declare loop variables
DECLARE @date2 datetime= CAST(CAST(@dt1 AS DATE) AS DATETIME)
set @date2 = DATEADD(HOUR, 13,@date2)
DECLARE @date1 datetime= DATEADD(DAY, -1, @date2)
--------------- Get Opening -------------------------------------------------------------------------------------------------
insert into @tbl_temp_min
select tbl.[FuelLevel],tbl.TankId ,@dt1
from [dbo].[FuelTankHistory] tbl
inner join (
select min(t.[FuelLevelTime]) [date],t.TankId
from [dbo].[FuelTankHistory] t
where t.[FuelLevelTime] between @date1 and @date2 and t.TankId in (1,2) and t.ProductId=1
group by t.TankId
) temp on tbl.TankId=temp.TankId and temp.[date]=tbl.[FuelLevelTime]
--------------- Get Closing -------------------------------------------------------------------------------------------------
insert into @tbl_temp_max
select tbl.[FuelLevel],tbl.TankId ,@dt1
from [dbo].[FuelTankHistory] tbl
inner join (
select max(t.[FuelLevelTime]) [date],t.TankId
from [dbo].[FuelTankHistory] t
where t.[FuelLevelTime] between @date1 and @date2 and t.TankId in (1,2) and t.ProductId=1
group by t.TankId
) temp on tbl.TankId=temp.TankId and temp.[date]=tbl.[FuelLevelTime]
----------------------------------------------------------------------------------------------------------------
SET @dt1= DATEADD(DAY, 1, @dt1)
END
select ReportDate,sum(sale) sale_petrol from
(select [max].*,ISNULL([min].min_fuelLevel, 0 ) [min_fuelLevel],(ISNULL([max].max_fuelLevel, 0 )-ISNULL([min].min_fuelLevel, 0 )) sale from @tbl_temp_max [max]
full join @tbl_temp_min [min] on [max].ReportDate=[min].ReportDate and [max].FuelStationTankId=[min].FuelStationTankId) total
group by ReportDate;
MODIFIED CONTENT
One more thing is I want the opening stock of current date should be equal to closing stock of previous date. I have millions of data which have hundreds of records for a minute. and this query skips one or more record while getting opening stock for current day.For example 2021-08-01 12:59:45 level is 100 & 2021-08-01 13:00:01 level is 90. now previous day closing level is 100 and current day opening level is 90 which is not acceptable. current day opening should be 100 also.