SQL Nested Multiple Select Statement - sql

Im trying to create a nested SQL statement with multiple Nested Select Statements, to be used on a record set import in excel vba.
What i want to do is create something like:
SELECT
N.LimitN,
Sum(N.amountN),
Sum(N1.amountN1)
FROM (
SELECT year as yearN, Sum(amount) as amountN, limit as limitN
FROM table1
WHERE year = 2013
GROUP BY year, limit) as N
JOIN (
SELECT year as yearN1, Sum(amount) as amountN1, limit as limitN1
FROM table1
WHERE year = 2014
GROUP BY year, limit) as N1
ON N.LimitN = N1.LimitN1
GROUP BY N.LimitN
ORDER BY N.LimitN;
So that if my Raw data is like this:
Year Amount Limit
2013 100 20
2013 90 30
2013 120 40
2013 5 20
2013 100 30
2013 105 40
2013 150 50
2014 115 20
2014 50 30
2014 95 40
2014 110 50
2014 30 20
My Resulting Table/record set will be like this:
Limit AmountN (i.e. 2013) Amount N1 (i.e. 2014)
20 105 145
30 190 50
40 225 95
50 150 110
Thanks in Advance
Peter

It feels like you're overcomplicating the query a little, what you want is just a year wise sum of amount, grouped by limit. This can be done using a CASE;
SELECT
limit,
SUM(CASE WHEN year=2013 THEN amount ELSE 0 END) amountN,
SUM(CASE WHEN year=2014 THEN amount ELSE 0 END) amountN1
FROM myTable
GROUP BY limit
ORDER BY limit;
An SQLfiddle to test with.
(if we're talking Access here, you will need to use IIF instead of CASE)

Related

How to drop a field from a running count

I am tasked with trying to come up with a total count for the number of clients we have had in any given year. I am able to run a total count of the clients we have had, but I want to drop them from the running total when they offboard from us (i.e. #EndDate)
DECLARE #EndDate Date
SET #EndDate = (SELECT DISTINCT LOAEndDate FROM tblCompany)
SELECT DISTINCT Year(DateBecameClient) AS [Year],
Count(CompanyId) OVER (ORDER BY Year(DateBecameClient)) AS NumberofClients
FROM [tblCompany] AS Company
ORDER BY [Year]
Here is the output that I get without including #EndDate.
--------------------
Year NumberofClients
2001 3
2002 6
2003 9
2004 10
2005 13
2006 15
2007 16
2008 26
2009 36
2010 78
2011 135
2012 204
2013 314
2014 385
2015 456
2016 471
2017 496
2018 507
2019 513
2020 514
2021 516
I presume that you have a separate date that indicates when the client left. You'll want to counterbalance with a -1 via a union. If a client was added and lost within the same year it'll never be counted:
with data as (
select year(DateBecameClient) as yr, 1 as num
from tblCompany
union all
select year(DateLostClient), -1
from tblCompany
)
select yr as "Year", sum(sum(num)) over (order by yr) as NumberOfClients
from data
group by yr
order by "Year";
I'm using grouping with a sum of sums to get around needing distinct. This is basically the same as your query except for the addition of the negative counters.

How to bring corresponding data in the column

How to bring the corresponding data in new columns by comparing there other attributes. here in the below table we have 2 weeks of data along with Store ID and Price type, if the price type is "Regular" then we have to add "Reduced" price with same criteria (Year, Week, StoreID) in the new column and if the price type is "Reduced" then we have to add "Regular" price with same criteria (Year, Week, StoreID) in the new column.
Year
Week
StoreID
PriceType
Price
2021
10
S
Regular
200
2021
10
S
Reduced
150
2021
10
D
Regular
180
2021
10
D
Reduced
120
2021
9
S
Regular
35
2021
9
D
Reduced
40
Has to be change like the below table, in the below output table, "Reduced/Regular" value is 150 in row number 1 because 150 is the corresponding value for 200 with criteria (2021, 10, S) and in 2nd row the Reduced/Regular value is 200 because 200 is the corresponding vale for 150 with criteria (2021, 10, S).
But last 2 rows for week 9 will gives 0 because we don't have corresponding criteria.
Year
Week
StoreID
PriceType
Price
Reduced/Regular
2021
10
S
Regular
200
150
2021
10
S
Reduced
150
200
2021
10
D
Regular
180
120
2021
10
D
Reduced
120
180
2021
9
S
Regular
35
0
2021
9
D
Reduced
40
0
Kindly help with this logic Thanks in advance
You can use window functions and conditional logic:
select t.*,
(case when priceType = 'Regular'
then max(case when priceType = 'Reduced' then price end) over (partition by year, week, storeId)
else max(case when priceType = 'Regular' then price end) over (partition by year, week, storeId)
end) as other_price
from t;
Happily, this is standard SQL and will work in any database.

Get multiple counts by 5 year increments

This is my table:
index_melanoma_yr Total_Melanoma Total_Virus
2000 700 12
2001 746 7
2002 724 12
2003 815 15
2004 893 16
2005 1020 22
I would like to count by 5 year increments. So, 2000-2004, 2005-2009, etc. I can hard code this, but since there are so many years, I'm wondering if there is a more efficient way.
Here's how I got the initial counts:
SELECT index_melanoma_yr,
COUNT(DISTINCT PersonID) AS Total_Melanoma,
SUM( CASE
WHEN index_virus_yr IS NOT NULL THEN
1
ELSE
0
END
) AS Total_Virus
FROM Asare_ViralMelanoma_IndexDates
GROUP BY index_melanoma_yr
ORDER BY index_melanoma_yr
you can perform some simple maths year / 5 * 5 on the year column, and then GROUP BY that. Assuming that the year column is integer
SELECT MIN(index_melanoma_yr) AS Year_Start,
MAX(index_melanoma_yr) AS Year_End,
COUNT(DISTINCT PersonID) AS Total_Melanoma,
SUM( CASE
WHEN index_virus_yr IS NOT NULL THEN
1
ELSE
0
END
) AS Total_Virus
FROM Asare_ViralMelanoma_IndexDates
GROUP BY index_melanoma_yr / 5 * 5
ORDER BY Year_Start

Cumulative Compoud Interest Calculation(Oracle Database 11g Release 2)

I have a requirement to calculate rolling compound interest on several accounts in pl/sql. I was looking for help/advice on how to script calculate these calculations. The calculations I need are in the last two columns of the output below (INTERESTAMOUNT AND RUNNING TOTAL). I found similar examples of this on here, but nothing specifically fitting these requirements in pl/sql. I am also new to CTE/Recursive Techniques and the Model technique I found required a specific iteration which would be variable in this case. Please see my problem below:
Calculations:
INTERESTAMOUNT = (Previous Year RUNNING TOTAL+ Current Year AMOUNT) * INTEREST_RATE
RUNNINGTOTAL = (Previous Year RUNNING TOTAL+ Current Year AMOUNT) * (1 + INTEREST_RATE) - CURRENT YEAR EXPENSES
Input Table:
YEAR ACCT_ID AMOUNT INTEREST_RATE EXPENSES
2002 1 1000 0.05315 70
2003 1 1500 0.04213 80
2004 1 800 0.03215 75
2005 1 950 0.02563 78
2000 2 750 0.07532 79
2001 2 600 0.06251 75
2002 2 300 0.05315 70
Desired Output:
YEAR ACCT_ID AMOUNT INTEREST_RATE EXPENSES INTERESTAMOUNT RUNNINGTOTAL
2002 1 1000 0.05315 70 53.15 983.15
2003 1 1500 0.04213 80 104.62 2507.77
2004 1 800 0.03215 75 106.34 3339.11
2005 1 950 0.02563 78 109.93 4321.04
2000 2 750 0.07532 79 56.49 727.49
2001 2 600 0.06251 75 82.98 1335.47
2002 2 300 0.05315 70 86.93 1652.4
One way to do it is with a recursive cte.
with rownums as (select t.*
,row_number() over(partition by acct_id order by yr) as rn
from t) -- t is your tablename
,cte(rn,yr,acct_id,amount,interest_rate,expenses,running_total,interest_amount) as
(select rn,yr,acct_id,amount,interest_rate,expenses
,(amount*(1+interest_rate))-expenses
,amount*interest_rate
from rownums
where rn=1
union all
select t.rn,t.yr,t.acct_id,t.amount,t.interest_rate,t.expenses
,((c.running_total+t.amount)*(1+t.interest_rate))-t.expenses
,(c.running_total+t.amount)*t.interest_rate
from cte c
join rownums t on t.acct_id=c.acct_id and t.rn=c.rn+1
)
select * from cte
Sample Demo
Generate row numbers using row_number function
Calculate the interest and running total of the first row for each acct_id (anchor in the recursive cte).
Join every row to the next one (ordered by ascending order of year column) for each account_id and compute the running total and interest for the subsequent rows.

T-SQL previous year total in next year column

I currently have a table that looks like this:
fscYear ID Days #Invoices AVG
2011 20000807 221 7 27
2012 20000807 403 15 25
2013 20000807 390 14 26
2014 20000807 119 4 23
I would like to include the previous year's AVG in the next year, like so:
fscYear ID Days #Invoices AVG prevAVG
2011 20000807 221 7 27 0
2012 20000807 403 15 25 27
2013 20000807 390 14 26 25
2014 20000807 119 4 23 26
How I can achieve that?
edit the SQL is straightforward,
select * from theTableThatHoldsThedata
Most databases support ANSI standard window functions. You can do this with lag():
select t.*, coalesce(lag(avg) over (order by by fscyear), 0) as prevAVG
from atable t;
This will work in SQL Server 2012+. For earlier versions, you can use a correlated subquery or apply:
select t.*, coalesce(tprev.prevAvg, 0) as prevAvg
from atable t outer apply
(select top 1 t2.Avg as prevAvg
from atable t2
where t2.fscyear < t.fscyear
order by t2.fscyear desc
) tprev;
You can write as:
SELECT Cur.fscYear ,Cur.ID,Cur.Days,Cur.#Invoices,Cur.AVG,
isnull(Prv.AVG,0) AS prevAVG
FROM test AS Cur
LEFT OUTER JOIN test AS Prv
ON Cur.fscYear = Prv.fscYear + 1;
Demo