Payment analysis - SQL server query - sql-server

Please can someone give me some pointers.
We are required to send out a Statutory Arrears Notification.
The criteria for sending it out is when an account has missed 2 full payments or the equivalent of. I.e if they are due to pay £100 a month but only paid £50 over 4 months, they are due the notice.
I have pulled a query which separates out the Repayment Schedule into date ranges, and between each range I have tallied up the payments made within that period. Also for each result I have tallied up DueToDate and PaidToDate.
The issue I have is working out some form of scoring system for each row, then at the end of the query, tally up to give an overall score which determines if the notice is due or not.
Results structure is like this.
DueDate | DateFrom | DateTo | AmountDue | AmountPaid | DueToDate | PaidToDate

If you mean that you already have a query that produces a result set like the following
DueDate | DateFrom | DateTo | AmountDue | AmountPaid | DueToDate | PaidToDate
20120301 | 20120201 | 20120229 | 100.00 | 50.00 | 100.00 | 50.00
20120401 | 20120301 | 20120331 | 100.00 | 50.00 | 200.00 | 100.00
20120501 | 20120401 | 20120430 | 100.00 | 50.00 | 300.00 | 150.00
20120601 | 20120501 | 20120531 | 100.00 | 50.00 | 400.00 | 200.00
Then here are two ways forward depending on whether the AmountDue per month is constant. If it is, then you can use
select *
from QueryResult
where DueToDate - PaidToDate >= 2 * AmountPaid;
If it is not constant, then you can use LAG() in SQL Server 2012 to add AmountPaid from the prior row to the current
;WITH Lagged AS (
select *, PriorAmount = LAG(AmountPaid, 1, 0) OVER (order by DueDate)
from QueryResult
)
select *
from Lagged
where DueToDate - PaidToDate >= AmountPaid + PriorAmount;
Or just keep a running total in yet another column in your original query, e.g.
DueDate | DateFrom | DateTo | AmountDue | AmountPaid | DueToDate | PaidToDate | TwoPeriods
20120301 | 20120201 | 20120229 | 100.00 | 50.00 | 100.00 | 50.00 | 100.00
20120401 | 20120301 | 20120331 | 100.00 | 50.00 | 200.00 | 100.00 | 200.00
20120501 | 20120401 | 20120430 | 100.00 | 50.00 | 300.00 | 150.00 | 200.00
20120601 | 20120501 | 20120531 | 100.00 | 50.00 | 400.00 | 200.00 | 200.00

Related

How to generate IDs based on column values

I will provide examples and code where I can. Assume everything except [CycleStart] and [CycleEnd] datatypes are Varchar, I'm not too fussed about this at this stage.
Table A consists of the following RAW sample data:
+-------+---------+----------------+------------+------------+
| JobID | JobName | CycleDesc | CycleStart | CycleEnd |
+-------+---------+----------------+------------+------------+
| 10003 | Run1 | January 2019 | 31/12/2018 | 31/12/2018 |
| 10005 | Run2 | December 2018 | 31/12/2017 | 31/11/2018 |
| 10006 | Run3 | March 2019 | 31/12/2018 | 31/02/2019 |
| 10007 | Run4 | September 2019 | 31/12/2018 | 31/09/2019 |
| 10008 | Run5 | November 2019 | 31/12/2018 | 31/10/2019 |
+-------+---------+----------------+------------+------------+
Table B consists of the following sample data and the code used to generate this data is below:
+-------+---------+---------+
| JobID | PeriodID | Entity |
+-------+---------+---------+
| 10003 | 202101 | XYZ1 |
| 10003 | 202112 | XYZ2 |
| 10007 | 202008 | XYZ3 |
| 10007 | 202003 | XYZ4 |
| 10008 | 201904 | XYZ5 |
+-------+----------+--------+
Declare #Counter3 INT
SELECT #Counter3=1
WHILE #Counter3 <= 1000
BEGIN
INSERT INTO [dbo].[TableB]
SELECT
FLOOR(RAND()*(33979-1+1))+1 [JobID]
,CAST(ROUND(((2021 - 2019 -1) * RAND() + 2020), 0) AS VARCHAR) + RIGHT('0'+CAST(FLOOR(RAND()*(12-1+1))+1 AS VARCHAR),2) [PeriodID]
,FLOOR(RAND()*(23396-1+1))+1 [Entity]
The issue lies within Table B column [PeriodID]. This column represents an ID generated from [CycleStart] in Table A e.g. 31/12/2018 = 201812 (YYYYMM).
What I want to show in Table B is a Period ID for each Job ID but show EACH month + 30 years ahead of the [CycleStart] date. Example table of what I am looking to achieve:
+-------+---------+---------+
| JobID | PeriodID | Entity |
+-------+---------+---------+
| 10006 | 201812 | XYZ1 |
| 10006 | 201901 | XYZ2 |
| 10006 | 201902 | XYZ3 |
| 10006 | 201903 | XYZ4 |
| 10006 | 201904 | XYZ5 |
| 10006 | 201905 | XYZ5 |
| 10006 | 201906 | XYZ5 |
| 10006 | 201907 | XYZ5 |
| ... | +30yrs | ... |
| 10006 | 204812 | XYZ5 |
+-------+----------+--------+
How can I achieve this? Currently I am just randomly generating IDs which is not related to the [CycleStart] date and therefore just skewing my data but this is the only way I can think of doing it.
The best way is to create a calendar table / date dimension. You can use this table to solve this issue, and reuse it for other problems later. (Search online for some examples on how to build one).
If you have this table then you only need to join this table and that's it.
e.g.
INSERT INTO TableB ( JobID , PeriodID)
SELECT DISTINCT A.JobID , D.TheYear * 100 + D.TheMonth
FROM tableA A
JOIN myDateTable D
ON D.TheDate BETWEEN CONVERT(date , A.CycleStart , 103) AND DATEADD(YEAR,30, CONVERT(date , A.CycleStart , 103));

Calculate user formula from account number

I have two tables, the first one is dbo.formula
Id | Poste | Calculation | Montant
---+--------+-------------+--------
1 | Achats | 3801%+381% | .....
2 | Tva | 446%-445% | ....
3 | Tiers | 411%+401% | ....
The second table is dbo.value
Compte | Solde
--------+-------
380000 | 400.00
380100 | 500.00
381100 | 200.00
381200 | 100.00
4456600 | 100.00
4455400 | 150.00
I need to be the result in the first table in field Montant like
800.00
50.00
I tried a request but it changes only the 3 beginning compute.
Join the tables on your conditions and aggregate:
select f.ID, f.Poste, sum(v.Solde) total
from formula f inner join value v
on charindex('+' + left(v.Compte, 3) + '%', '+' + f.Calculation) > 0
group by f.ID, f.Poste
See the demo.
Results:
> ID | Poste | total
> -: | :----- | :------
> 1 | Achats | 1200.00
> 2 | Tva | 250.00

SQL Server : query to display new column containing data * factor based on previous record

I am trying to formulate a query in SQL Server where:
Date | Name | Amount | AmountX
------------+---------+--------+-------
2010-01-01 | Test | 0 | 0
2010-02-01 | Test | 0 | 0
2010-03-01 | Test | 0 | 0
2011-01-01 | Test | 62.61 | 63.86
2011-02-01 | Test | 62.61 | 63.86
2011-03-01 | Test | 62.61 | 63.86
2012-01-01 | Test | 62.61 | 65.14
2012-02-01 | Test | 62.61 | 65.14
2012-03-01 | Test | 62.61 | 65.14
2013-01-01 | Test | 62.61 | 66.44
2013-02-01 | Test | 62.61 | 66.44
2013-03-01 | Test | 62.61 | 66.44
2014-01-01 | Test | 62.61 | 67.77
2014-02-01 | Test | 62.61 | 67.77
2014-03-01 | Test | 62.61 | 67.77
2015-01-01 | Test | 0 | 0
2015-02-01 | Test | 0 | 0
2015-03-01 | Test | 0 | 0
2016-01-01 | Test | 67.95 | 69.31
2016-02-01 | Test | 67.95 | 69.31
2016-03-01 | Test | 67.95 | 69.31
2017-01-01 | Test | 67.95 | 70.70
2017-02-01 | Test | 67.95 | 70.70
2017-03-01 | Test | 67.95 | 70.70
2018-01-01 | Test | 67.95 | 72.11
2018-02-01 | Test | 67.95 | 72.11
2018-03-01 | Test | 67.95 | 72.11
2019-01-01 | Test | 67.95 | 73.55
2019-02-01 | Test | 67.95 | 73.55
2019-03-01 | Test | 67.95 | 73.55
The Date, Name and Amount columns come from the table.
I need to create a query to include to AmountX column based on the Date grouping. The Amount and a factor of 2% for calculation.
Year 2010 can be ignored because the Amount values are 0s.
For the year 2011, the Amount values are none 0s which is 62.61. I need to multiply that by 1.02 giving 63.86, for the whole year and display it in the AmountX column.
Now for the year 2012, it will be calculated 63.86 for previous year X 1.02 = 65.14.
So for 2013, it will be 64.14 X 1.02 = 66.44.
And for 2014, it will be 66.44 X 1.02 = 67.77.
Is this doable?
Any help is greatly appreciated.
RS..
I think you want:
select t.*,
(amount * power(1.02, year(date) - 2010)) as amountX
from t;

SQL Server : new column based on other columns

I want to calculate a new value for the new column based on other columns in T-SQL.
My data is look like this:
Each row represents one person in one day.
The WorkHours is calculated based on the Portion column:
Round(FF.Portion * 7.4, 3) AS WorkHours
I want to calculate a percentage of hours which people not have been at work in relation to the TOTAL workhours for day for each school. For example if 10 people work full hour in one school for one day, it gives 74 working hours and if one person have been sick that day it will give (7,4 % 74 * 100) which is 10% (the WorkHours is calculated based on Portion column)
In your comment you state Peter had 6 hours on 1/1/2017 as "seek" but it was actually 7.4. With that in mind, we can calculate your results as follows:
declare #table table (Name varchar(16), Date date, School char(2), FreedayCode int, Freeday varchar(64), Portion decimal (6,4))
insert into #table
values
('Mike','20170101','AA',-1,'AtWork',1),
('Mike','20170201','AA',1,'Seek',1),
('Ali','20170101','BB',-1,'AtWork',0.94594),
('Ali','20170201','BB',-1,'AtWork',0.94594),
('Sara','20170101','CC',2,'holiday',1),
('Sara','20170201','CC',1,'Seek',1),
('Peter','20170101','AA',1,'Seek',1),
('Peter','20170201','AA',1,'Seek',1),
('Nina','20170101','AA',-1,'AtWork',0.81081),
('Nina','20170201','AA',-1,'AtWork',0.81081)
select
Name
,Date
,School
,FreeDayCode
,Freeday,Portion
,NewColumn = sum(case when Freeday <> 'AtWork' then Round(Portion * 7.4,3) else 0 end) over (partition by Date, School) / sum(Round(Portion * 7.4,3)) over (partition by Date, School)
from
#table
order by
Date
,School
RETURNS
+-------+------------+--------+-------------+---------+---------+-----------+
| Name | Date | School | FreeDayCode | Freeday | Portion | NewColumn |
+-------+------------+--------+-------------+---------+---------+-----------+
| Mike | 2017-01-01 | AA | -1 | AtWork | 1.0000 | 0.355769 |
| Peter | 2017-01-01 | AA | 1 | Seek | 1.0000 | 0.355769 |
| Nina | 2017-01-01 | AA | -1 | AtWork | 0.8108 | 0.355769 |
| Ali | 2017-01-01 | BB | -1 | AtWork | 0.9459 | 0.000000 |
| Sara | 2017-01-01 | CC | 2 | holiday | 1.0000 | 1.000000 |
| Peter | 2017-02-01 | AA | 1 | Seek | 1.0000 | 0.711538 |
| Mike | 2017-02-01 | AA | 1 | Seek | 1.0000 | 0.711538 |
| Nina | 2017-02-01 | AA | -1 | AtWork | 0.8108 | 0.711538 |
| Ali | 2017-02-01 | BB | -1 | AtWork | 0.9459 | 0.000000 |
| Sara | 2017-02-01 | CC | 1 | Seek | 1.0000 | 1.000000 |
+-------+------------+--------+-------------+---------+---------+-----------+

Moving average in Temporal database in PostgreSQL

How can I apply the moving average in temporal database.
My data includes temperature and I want to apply moving average for every 15 records.
You can fire query as below
marc=# SELECT entity, name, salary, start_date,
avg(salary) OVER (ORDER BY entity, start_date
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
FROM salary;
entity | name | salary | start_date | avg
-----------+-----------+---------+---------------+----------------------
Accounting | millicent | 850.00 | 2006-01-01 | 825.0000000000000000
Accounting | jack | 800.00 | 2010-05-01 | 916.6666666666666667
R&D | tom | 1100.00 | 2005-01-01 | 966.6666666666666667
R&D | john | 1000.00 | 2008-07-01 | 933.3333333333333333
R&D | maria | 700.00 | 2009-01-01 | 733.3333333333333333
R&D | kevin | 500.00 | 2009-05-01 | 633.3333333333333333
R&D | marc | 700.00 | 2010-02-15 | 600.0000000000000000
WITH moving_avrag AS (
SELECT 0 AS [lag] UNION ALL
SELECT 1 AS [lag] UNION ALL
SELECT 2 AS [lag] UNION ALL
SELECT 3 AS [lag] --ETC
)
SELECT
DATEADD(day,[lag],[date]) AS [reference_date],
[otherkey1],[otherkey2],[otherkey3],
AVG([value1]) AS [avg_value1],
AVG([value2]) AS [avg_value2]
FROM [data_table]
CROSS JOIN moving_avg
GROUP BY [otherkey1],[otherkey2],[otherkey3],DATEADD(day,[lag],[date])
ORDER BY [otherkey1],[otherkey2],[otherkey3],[reference_date];

Resources