Calculate average monthly mileage - sql-server

I have a list of fleet vehicles that I'm attempting to calculate the average monthly and yearly mileage of.
For example, vehicle 1970 was manufactured in 2015, and has a current odometer of 105,341. That means the truck is 2 years or 24 months old. So the yearly average is 52,670 miles and the monthly average is 4,389.
I'm selecting the vehicle number, year of mfg., and the current odometer reading.
The field M.ManufacturerYear is data type int and O.MeterLevel is data type varchar
How would I write the calculated fields to return the monthly and yearly average for each vehicle in the list?

Perhaps an alternative of calculating the actual number of months and then annualizing (or normalizing) the results.
In the example below, Vehicle 2020 is only 7 months old, but the annualized mileage is greater than Vehicle 1970
Example
Declare #YourTable Table ([Vehicle] varchar(50),ManufacturerYear int,[Odometer] int)
Insert Into #YourTable Values
(1970,2015,105341)
,(2020,2017,25253)
Select *
,NbrMonths = datediff(month,left(ManufacturerYear,4) +'0101',GetDate())
,PerMonth = [Odometer] / datediff(month,left(ManufacturerYear,4) +'0101',GetDate())
,Annualized = ([Odometer] / datediff(month,left(ManufacturerYear,4) +'0101',GetDate()) ) * 12
From #YourTable
Returns

The below sample code is for similar scenario in MS SQL Server.
CREATE TABLE #Vehicle
(
VehicldId int,
YearOfManufacture smallint,
TotalMiles int,
AverageYearlyMiles AS TotalMiles / (YEAR(GETDATE()) - YearOfManufacture),
AverageMonthlyMiles AS TotalMiles / ((YEAR(GETDATE()) - YearOfManufacture) * 12 + MONTH(GETDATE()))
)
insert into #Vehicle(VehicldId,YearOfManufacture,TotalMiles)
values ( 1970,2015,105400)
SELECT * FROM #Vehicle

Related

Netezza SQL how to calculate daily compound interest with varying rates

I’m having trouble figuring out how to calculate the daily compound interest for an initial amount, over various rates periods, producing a new total that includes the interest amounts from each rate period. The challenge is that for each subsequent rate period you have to calculate the interest on the amount plus the previous interest!!! So it’s not a simple running total.
For example, using the following rates table.
rate from date rate to date rate
-------------- ------------ ----
2013-07-15 2013-09-30 3
2013-10-01 2013-12-31 4
2014-01-01 2014-03-31 3
Using an initial amount of $32,550.37, I have to traverse each rate period with an interest calculation, producing the final amount of $33,337.34.
rate from date rate to date rate daysx amount interest
-------------- ------------ ---- ----- ---------- --------
2013-07-15 2013-09-30 .03 78 32,550.37 209.34
2013-10-01 2013-12-31 .04 92 32,759.71 331.94
2014-01-01 2014-03-31 .03 90 33,091.65 245.69
Final Amount 33,337.34
For example, the initial amount of $32,550.37 has interest of $209.34 at 3%. For the second rate period, I add that interest to the amount, which is $32,759.71 and then calculate the interest on $32,759.71 at 4%. Etc.
I’m using Netezza which does not allow recursive SQL, so I have been trying to use windowed functions, but not with any success yet …
DROP TABLE TRATES;
CREATE TABLE TRATES (RATE_FROM_DATE DATE, RATE_TO_DATE DATE, RATE DECIMAL(10,2));
INSERT INTO TRATES VALUES ('2013-07-15','2013-09-30',.03);
INSERT INTO TRATES VALUES ('2013-10-01','2013-12-31',.04);
INSERT INTO TRATES VALUES ('2014-01-01','2014-03-31',.03);
SELECT TRATES.*
, DAYS_BETWEEN(RATE_FROM_DATE, RATE_TO_DATE)+1 AS DAYSX
, (AMOUNT * POW(1+(RATE)/365,(DAYS_BETWEEN(RATE_FROM_DATE, RATE_TO_DATE)+1)))) – AMOUNT
AS INTEREST
, FIRST_VALUE(AMOUNT) OVER(ORDER BY RATE_FROM_DATE)
*(POW(1+(RATE/100)/365,(DAYS_BETWEEN(RATE_FROM_DATE, RATE_TO_DATE)+1)))
AS NEW_AMOUNT
FROM TRATES
JOIN (SELECT 32550.37 AS AMOUNT) AS TPARMS ON 1=1
;
Any help would be greatly appreciated.
I’m using the fact that the interest rate is shifting is not dependent on which order the shifts occur, so 3 days at 3% followed but 4 days at 2% gives the same result as 4 days at 2% followed by 3 days at 3%.
Furthermore summing logarithms will allow you to multiply over rows:
https://blog.jooq.org/2018/09/21/how-to-write-a-multiplication-aggregate-function-in-sql/
In short: log(a1)+log(a2)+..+log(an) = log(a1*a2*..*an)
This is pretty close to a useful solution (and performs reasonably):
DROP TABLE TRATES if exists;
CREATE temp TABLE TRATES (RATE_FROM_DATE DATE, RATE_TO_DATE DATE, RATE DECIMAL(10,2));
INSERT INTO TRATES VALUES ('2013-07-15','2013-09-30',.03);
INSERT INTO TRATES VALUES ('2013-10-01','2013-12-31',.04);
INSERT INTO TRATES VALUES ('2014-01-01','2014-03-31',.03);
create temp table dates as
select '2010-01-01'::date -1+row_number() over (order by null) as Date
from ( select * from
_v_dual_dslice a cross join _v_dual_dslice b cross join _v_dual_dslice c cross join _v_dual_dslice d
limit 10000 ) x
;
SELECT AMOUNT*pow(10,sum(log(1+rate::double/365)))
FROM TRATES join dates
on date between RATE_FROM_DATE and RATE_TO_DATE
JOIN (SELECT 32550.37 AS AMOUNT) AS TPARMS ON 1=1
group by AMOUNT
I'm sure you can make it prettier with a bit of effort and even let it return the results on select days in the 260 day interval if needed

Payroll computation

I need you to help me. I have to do a program that calculates the payroll in Management Sql Server 2014. The program should be something like that:
The salary is the sum of gross salary and paid holidays: Sal = Gross_ Salary + Paid_Holiday
For the computation of the Paid_ Holiday we need:
The salary from the previous 6 months:
Sal_6 + Sal_5 + Sal_4 + Sal_3 + Sal_2 + Sal_1 = Base
With Sal_6 = GrossSal_6 + Paid_Holiday_6 ( as i said above)
...
The number of days worked or holiday days from the previous 6 months:
NOdays_6 + NOdays_5 + NOdays_4 + NOdays_3 + NOdays_2 + NOdays_1 = SumOfDays
The paid holiday is: Paid_Holiday= BASE/SumOfDays * NOdays.
From the database I have the following tables:
Entry ( Identry, Gross_Salary, NOdayworked, Date, IDEmplyee )
Employee (IDEmplyee, Name, DateofEmployment)
Holiday ( IDHoliday, StartDate, FinalDate, IDEmployee)
The employee has an seniority certificate with the last 6 salaries from the previous employer.
Certificate ( IdCertificate, date, Gross_Salary, NOdayworked, Paid_Holiday, NOdays, IDEmployee)
Because I need the last paid holidays and salary to form the gross salary I thought that I should used a temporary table. This table will retain the data from the certificate and the data from Entry
What I have tried so far is the following stored procedure:
create proc payroll
#idemployee int
as
create table #tmp( id int identity(1,1) primary key, date1 date, grosssalary money, idemployee int, nodaysworked int, paidholiday money, noofdays int)
insert into #tmp ( date1 , grosssalary , idemployee , nodaysworked , paidholiday , noofdays )
Select Top 6 Date,
Gross_Salary,
IDEmployee,
NOdayworked,
Paid_Holiday,
IDEmployee
from Certificate
WHERE IDEmployee = #idemployee
ORDER BY Date asc
And after that I have to take for every paidholiday the last 6 Salary
Paid_Holiday= BASE/SumOfDays * NOdays but I don't know exactly how I should do. I thought about a cursor or something.
PS: If you didn't understand please let me know. My mother tongue is not English ( also this program is not available for all the countries.
The program is valid in Romania)

SQL server: smoothed average of day of year

I have a subquery with avg reservoir inflow pr day of year (from 1-365). Now I would like to calculate a smoothed/moving average for each day of year in a new column.
Example: for january 1st (DayOfYear = 1) I would like to calculate a smoothed average of 21 days (10 pre and 10 post days). I.e an avg of days ranging from (356-11). For day of year 55 the avg should be calculated on days of the year ranging from (45-65).
Her is the unfinished query based on a subquery called 'sub' where the 10 years of inflow first are averaged on day of year;
DECLARE #Dager int ;
SET #Dager = 10; /* # days pre and post the actual day of year to be included in avg */
Select sub.Magasin, sub.DayOfYear, AVG(sub.Inflow) as AvgInflow
FROM (SELECT Date, Magasin, Datepart(dy,Date) as DayOfYear, Value as Inflow
FROM inputtable
WHERE Date >= DATEFROMPARTS(2008,1,1) and Date <= DATEFROMPARTS(2017,12,31)) sub
GROUP By sub.Magasin, sub.DayOfYear
ORDER BY sub.magasin, sub.DayOfYear
Without any sample data, I'm going to suggest this for SQL Server 2012+
(Your SQL looks like SQL Server 2012+)
SELECT
Magasin,
Datepart(dy,Date) AS DayOfYear,
AVG(Inflow) OVER (
PARTITION BY Magasin
ORDER BY YEAR(Date), Datepart(dy,Date)
ROWS BETWEEN 10 PRECEDING AND 10 FOLLOWING)
FROM
inputtable
WHERE
Date >= DATEFROMPARTS(2008,1,1) and Date <= DATEFROMPARTS(2017,12,31))

Compare the dates, compute the difference between them, postgres

I have a date column and a balance column for each user. Every time user makes a transaction, a new row gets added to this table. It could be that the user makes 15 transactions during the day, and no transaction at all during 5 days.
Like this one
date balance
2017-06-01 95.63
2017-06-01 97.13
2017-06-01 72.14
2017-06-06 45.04
2017-06-08 20.04
2017-06-09 10.63
2017-06-09 -29.37
2017-06-09 -51.35
2017-06-13 -107.55
2017-06-13 -101.35
2017-06-15 -157.55
2017-06-16 -159.55
2017-06-17 -161.55
The goal is to select the positive and negative transactions made during the same day, compute their average or min value and to consider it as one transaction.If the next day no transaction has been made, then the amount of the previous day should be used.
it means for each day in a month i should calculate an interest and it the balance has not been updated then the balance of the previous day should be used.
Hypothetically my table should look like
date balance
1/6/2017 72.14
6/2/2017 72.14
6/3/2017 72.14
6/4/2017 72.14
6/5/2017 72.14
6/6/2017 45.04
7/6/2017 45.04
8/6/2017 20.04
9/6/2017 -51.35
10/6/2017 -51.35
11/6/2017 -51.35
12/6/2017 -51.35
13/06/2017 -107.55
14/06/2017 -107.55
15/06/2017 -157.55
16/06/2017 -159.55
17/06/2017 -161.55
i have added those days that were missing and group the days that were duplicate.
Once I have this done, I can select the number of positive balance days, e.g. 8 days, compute the average positive balance, and multiply it by 0.4%.
8*58.8525*0.004=0.23
The same should be done with negative balance. but with a different interest rate number of negative balance days, e.g. 9 multiplied by average negative balance during those days and 8.49%.
9*-99.90555556*0.00849=-0.848
So my expected result is just to have these two columns
Neg Pos
-0.848 0.23
How can I do that it in postgres? The function OVERLAP does not really help since I need to specify the dates.
Besides i do not know how to
loop the days and to see if there is a duplicate.
See which days are missing and use the previous balance for each of these missing days.
please try this.. replace table with your table name
with cte as
(
Select "date" as date
,min(balance) as balance
,lead("date") over(order by "date") next_date
,Coalesce(ABS("date" - lead("date") over(order by "date")),1) date_diff
from table
group by "date"
),
cte2 as
(
Select date_diff*balance as tot_bal , date_diff
from cte
Where balance > 0
),
cte3 as
(
Select date_diff*balance as tot_bal , date_diff
from cte
Where balance < 0
)
Select (sum(cte2.tot_bal) / sum(cte2.date_diff) ) * 0.004 as pos
,(sum(cte3.tot_bal) / sum(cte3.date_diff) ) * 0.00849 as neg
from cte2
,cte3;

How to Create budget table Using current Actual Table

I have Fact table with 6 metric columns and three date key columns remain all are foreign keys,I need design a Budget table based on that fact table like
1)Current year Budget =last year fact +10%(last year fact)
2)Current Quarter Budget =last Quarter fact +10%(last Quarter fact)
3)Current Month Budget =last Month fact +10%(last Month fact)
Does this pseudocode make any sense?
SELECT
DATEPART(YEAR, GETDATE()),
YearFact * 1.1 AS YearBudget,
QuarterFact * 1.1 AS QuarterBudget,
MonthFact * 1.1 AS MonthBudget
FROM
FactTable
WHERE
DATEPART(YEAR, FactDate) = DATEPART(YEAR, GETDATE()) - 1;

Resources