In SQL Server, how can I duplicate my current set of results for each month and increase them by 1.5* - sql

EDIT: I updated this post cause I had to change my table, I had to change my Quantity from an INT to varchar to accommodate for decimals and now the below answers won't work, is varchar the best option for this?
Sorry, this might be a bit of a simple question for someone who knows what they're doing but I'm super new to SQL.
I've created this table (60 results in total)
However these are just the results for the first month of the year (January)
all further results are the same except the quantity is a 1.5% increase per month, so in February (2016-02-01) the first employee's six quantity's would be
111
165
463
156
99
63
However I'm having trouble getting my head around using scripts to enter results. I could manually enter each month but that would take me quite a few hours as there's 60 results for each month. So I was thinking maybe I could copy the current contents of the table into a temporary variable then create some sort of loop that has a 1.5% increase for each month and also changes the date to the relevant month, but I have absolutely no idea how to go about doing this.
If anyone could help me out with how I could go about doing this I'd be super grateful, I'm so stumped and I don't even know where to start

You can add the next month by doing:
insert into t(employee_id, month, product_id, quantity)
select employee_id, dateadd(month, 1, [month]), product_id, quantity*(1 + 0.015)
from t
where t.[month] = '2016-01-01';
I would recommend that you just repeat this 11 times, changing the where clause each time. You can set up a query to do all 11 months at the same time, but it is probably not worth the effort.

You can do an INSERT/SELECT where your table is both source and target:
INSERT INTO tab
SELECT Sale_ID, Employee_ID, dateadd(month, 1, [Month]), Product_ID, Quantity * 1.015
FROM tab
WHERE [Month] = '2016-01-01'
Repeat this for 10 times and increase the number of months by one in each repetiton.
To do the inserts for all month in a single query you could add a CROSS JOIN to a series of numbers from 1 to 11:
INSERT INTO tab
SELECT Sale_ID, Employee_ID, dateadd(month, numbers.n, [Month]), Product_ID, Quantity * 1.015
FROM tab CROSS JOIN (select sale_ID AS n from tab where sale_ID between 1 and 11) AS numbers
WHERE [Month] = '2016-01-01'

Related

Automatically add rows based on schedule

I am currently building reports off a legacy system in SQL. The data is stored like the below.
Which I have now unpivoted, so this information is stored as a row per contract.
Here is what I am struggling to achieve, I am trying to build a payment schedule table for these contracts. The majority of them are fine as the "FirstPaymentDate" is the full payment we expect, however for some of them we receive the payment every 30 days until the contract is paid off.
So, in the example above, there is a contractvalue of 1000 and a sold term of 2 years. 1000/24 months = £41.6 per month. I need to display this as a table with each date that we expect payment up until the last date, such as the below
Not going to lie, I am struggling how to approach this. I have tried searching but not sure what labels I would search for to cover my issue.
Can anyone help with an approach to solve this? Even if it's just pointing me in the right direction?
You could do this with a recursive CTE. The code below outputs the desired result set you have shown. Your question asks for payments every 30 days but the desired result set example shows every month. This example shows a payment every month. If you need every 30 days you can update to DATEADD(DAY, 30, PaymentDate).
DROP TABLE IF EXISTS #Contract;
CREATE TABLE #Contract
(
ContractId INT
, SoldTerm INT
, FirstPaymentDate DATE
, ContractValue MONEY
, PaymentTerms INT
);
INSERT INTO #Contract VALUES (10222, 2, '01/04/2022', 1000, 30);
WITH ContractDates AS
(
SELECT ContractId, FirstPaymentDate AS PaymentDate, 1 AS Payment, (ContractValue / (SoldTerm * 12)) AS PaymentAmount, (SoldTerm * 12) AS LastPayment
FROM #Contract
UNION ALL
SELECT ContractId, DATEADD(MONTH, 1, PaymentDate), Payment + 1 AS Payment, PaymentAmount, LastPayment
FROM ContractDates
WHERE Payment + 1 <= LastPayment
)
SELECT * FROM ContractDates;
DROP TABLE IF EXISTS #Contract;

(Forecasting) Calculating the balance in the future

My product team has asked if I could create a very crude forecasting data table for them to work with. I have a pretty good idea on a lot of the steps I need to take, but I am stuck on figuring how to to calculate the Inventory Quantity for tomorrow, the next day, etc.
In my database, I am able to see our current quantity on hand. I would call that starting balance (for today). I am then going to create an average usage field and that will be my estimated daily sales. I will then take the starting balance - estimated daily sales = ending balance. I can do that for today, my question is how do I roll that formula forward for the next 120 days
You can use a recursive CTE to generate number from 0 to 120 and then calculate the day and balance with them.
DECLARE #estimated_daily_sales integer = 2;
DECLARE #starting_balance integer = 12345;
WITH
cte AS
(
SELECT 0 i
UNION ALL
SELECT i + 1 i
FROM cte
WHERE i + 1 <= 120
)
SELECT dateadd(day, i, convert(date, getdate())) day,
#starting_balance - i * #estimated_daily_sales balance
FROM cte
OPTION (MAXRECURSION 120);
db<>fiddle

Calculating a running count of Weeks

I am looking to calculate a running count of the weeks that have occurred since a starting point. The biggest problem here is that the calendar I am working on is not a traditional Gregorian calendar.
The easiest dimension to reference would be something like 'TWEEK' which actually tells you the week of the year that the record falls into.
Example data:
CREATE TABLE #foobar
( DateKey INT
,TWEEK INT
,CumWEEK INT
);
INSERT INTO #foobar (DateKey, TWEEK, CumWEEK)
VALUES(20150630, 1,1),
(20150701,1,1),
(20150702,1,1),
(20150703,1,1),
(20150704,1,1),
(20150705,1,1),
(20150706,1,1),
(20150707,2,2),
(20150708,2,2),
(20150709,2,2),
(20150710,2,2),
(20150711,2,2),
(20150712,2,2),
(20150713,2,2),
(20150714,1,3),
(20150715,1,3),
(20150716,1,3),
(20150717,1,3),
(20150718,1,3),
(20150719,1,3),
(20150720,1,3),
(20150721,2,4),
(20150722,2,4),
(20150723,2,4),
(20150724,2,4),
(20150725,2,4),
(20150726,2,4),
(20150727,2,4)
For sake of ease, I did not go all the way to 52, but you get the point. I am trying to recreate the 'CumWEEK' column. I have a column already that tells me the correct week of the year according to the weird calendar convention ('TWEEK').
I know this will involve some kind of OVER() windowing, but I cannot seem to figure It out.
The windowing function LAG() along with a summation of ORDER BY ROWS BETWEEN "Changes" should get you close enough to work with. The caveat to this is that the ORDER BY ROWS BETWEEN can only take an integer literal.
Year Rollover : I guess you could create another ranking level based on mod 52 to start the count fresh. So 53 would become year 2, week 1, not 53.
SELECT
* ,
SUM(ChangedRow) OVER (ORDER BY DateKey ROWS BETWEEN 99999 PRECEDING AND CURRENT ROW)
FROM
(
SELECT
DateKey,
TWEEK,
ChangedRow=CASE WHEN LAG(TWEEK) OVER (ORDER BY DateKey) <> TWEEK THEN 1 ELSE 0 END
FROM
#foobar F2
)AS DETAIL
Some minutes ago I answered a different question, in a way this is a similar question to
https://stackoverflow.com/a/31303395/5089204
The idea is roughly to create a table of a running number and find the weeks with modulo 7. This you could use as grouping in an OVER clause...
EDIT: Example
CREATE FUNCTION dbo.RunningNumber(#Counter AS INT)
RETURNS TABLE
AS
RETURN
SELECT TOP (#Counter) ROW_NUMBER() OVER(ORDER BY o.object_id) AS RunningNumber
FROM sys.objects AS o; --take any large table here...
GO
SELECT 'test',CAST(numbers.RunningNumber/7 AS INT)
FROM dbo.RunningNumber(100) AS numbers
Dividing by 7 "as INT" offers a quite nice grouping criteria.
Hope this helps...

Display a rolling 12 weeks chart in SSRS report

I am calling the data query in ssrs like this:
SELECT * FROM [DATABASE].[dbo].[mytable]
So, the current week is the last week from the query (e.g. 3/31 - 4/4) and each number represents the week before until we have reached the 12 weeks prior to this week and display in a point chart.
How can I accomplish grouping all the visits for all locations by weeks and adding it to the chart?
I suggest updating your SQL query to Group by a descending Dense_Rank of DatePart(Week,ARRIVED_DATE). In this example, I have one column for Visits because I couldn't tell which columns you were using to get your Visit count:
-- load some test data
if object_id('tempdb..#MyTable') is not null
drop table #MyTable
create table #MyTable(ARRIVED_DATE datetime,Visits int)
while (select count(*) from #MyTable) < 1000
begin
insert into #MyTable values
(dateadd(day,round(rand()*100,0),'2014-01-01'),round(rand()*1000,0))
end
-- Sum Visits by WeekNumber relative to today's WeekNumber
select
dense_rank() over(order by datepart(week,ARRIVED_DATE) desc) [Week],
sum(Visits) Visits
from #MyTable
where datepart(week,ARRIVED_DATE) >= datepart(week,getdate()) - 11
group by datepart(week,ARRIVED_DATE)
order by datepart(week,ARRIVED_DATE)
Let me know if I can provide any more detail to help you out.
You are going to want to do the grouping of the visits within SQL. You should be able to add a calculated column to your table which is something like WorkWeek and it should be calculated on the days difference from a certain day such as Sunday. This column will then by your X value rather than the date field you were using.
Here is a good article that goes into first day of week: First Day of Week

sql to calculate daily totals minues the previous day's totals

I have a table that has a date, item, and quantity.
I need a sql query to return the totals per day, but the total is the quantity minus the previous day totals. The quantity accumulates as the month goes on. So the 1st could have 5 the 2nd have 12 and the 3rd has 20.
So the 1st adds 5
2nd adds 7 to make 12
3rd adds 8 to make 20.
I've done something like this in the past, but can not find it or remember. I know i'll need a correlated sub-query.
TIA
--
Edit 1
I'm using Microsoft Access.
Date is a datetime field,
item is a text, and
quantity is number
--
Edit 2
Ok this is what i have
SELECT oos.report_date, oos.tech, oos.total_cpe, oos_2.total_cpe
FROM oos INNER JOIN (
SELECT oos_2.tech, Sum(oos_2.total_cpe) AS total_cpe
FROM oos_2
WHERE (((oos_2.report_date)<#10/10/2010#))
GROUP BY oos_2.tech
) oos_2 ON oos.tech = oos_2.tech;
How do i get the oos.report_date into where i says #10/10/2010#. I thought I could just stick it in there like mysql, but no luck. I'm gonna continue researching.
Sum them by adding one to the date and making the value negative, thus taking yesterday's total from today's:
SELECT report_date, tech, Sum(total_cpe) AS total_cpe
FROM (
SELECT oos.report_date, oos.tech, oos.total_cpe
FROM oos
UNION ALL
SELECT oos.report_date+1, oos.tech, 0-oos.total_cpe
FROM oos
)
WHERE (report_date < #10/10/2010#)
GROUP BY report_date, tech
ORDER BY report_date, tech
Ok, I figured it out.
SELECT o.report_date, o.tech, o.total_cpe,
o.total_cpe - (
SELECT IIf(Sum(oos.total_cpe) is null, 0,Sum(oos.total_cpe)) AS total_cpe
FROM oos
WHERE (((oos.tech)=o.tech) AND ((oos.report_date)<o.report_date))
) AS total
FROM oos o;