Looping across months - plsql

I have two tables say A ( Detail table) and B (summary table).
Transactions in table A fall into various months within a year. Table B has some fields defined to correspond to a particular month (as illustrated below). I want a procedure that will fetch records from Table A and update Table B such that the amounts for say month 1 will be summed up in YTDBAL_1, month 2 will be the sum of month 1 plus sum of month 2 (YTDBAL2) and so on such that the consecutive month will hold cumulative balances from beginning of year to date (current month).
Sample Data in Table A
OFFCD GLHEAD YEAR MONTH AMOUNT
010 10101001 2014 01 25,000.00
010 10101001 2014 01 5,000.00
010 10101001 2014 02 8,000.00
010 10101001 2014 02 4,000.00
010 10101001 2014 03 10,000.00
010 10101001 2014 04 10,000.00
010 10101001 2014 05 -4,000.00
010 10101001 2014 05 3,000.00
..
..
010 10101001 2014 12 1,000.00
Expected data in Table B
OFFCD GLHEAD YEAR YTDBAL_1 YTDBAL_2 YTDBAL_3 YTDBAL_4 YTDBAL_5 ..... YTDBAL_12
010 10101001 2014 30,000 42,000 52,000 62,000 61,000 XXX
My procedure below was populating all fields with same amount. How do i make it such that i arrive at above expected result.
NB: The transaction table has more than a million records and I am using Oracle 11g.
CREATE OR REPLACE PROCEDURE rectify_gl_bal(w_year Number)
IS
CURSOR gl_cur IS
Select * from nlmstdtl
where period_year=w_year;
TYPE gl_array IS TABLE OF gl_cur%ROWTYPE;
gldtl gl_array;
Begin
open gl_cur;
Loop
Fetch gl_cur bulk collect into gldtl limit 500;
EXIT WHEN gldtl.count = 0;
Forall x in 1..gldtl.count
update nlmst
set NLMST.YTDBAL_1 = NLMST.YTDBAL_1 + gldtl(x).amount,
NLMST.YTDBAL_2 = NLMST.YTDBAL_2 + gldtl(x).amount,
NLMST.YTDBAL_3 = NLMST.YTDBAL_3 + gldtl(x).amount,
NLMST.YTDBAL_4 = NLMST.YTDBAL_4 + gldtl(x).amount,
NLMST.YTDBAL_5 = NLMST.YTDBAL_5 + gldtl(x).amount,
NLMST.YTDBAL_6 = NLMST.YTDBAL_6 + gldtl(x).amount,
NLMST.YTDBAL_7 = NLMST.YTDBAL_7 + gldtl(x).amount,
NLMST.YTDBAL_8 = NLMST.YTDBAL_8 + gldtl(x).amount,
NLMST.YTDBAL_9 = NLMST.YTDBAL_9 + gldtl(x).amount,
NLMST.YTDBAL_10 = NLMST.YTDBAL_10 + gldtl(x).amount,
NLMST.YTDBAL_11 = NLMST.YTDBAL_11 + gldtl(x).amount,
NLMST.YTDBAL_12 = NLMST.YTDBAL_12 + gldtl(x).amount
where nlmst.offcd = gldtl(x).offcd and
nlmst.period_year = gldtl(x).period_year and
nlmst.glhead = gldtl(x).glhead;
End Loop;
commit;
close gl_cur;
End;

It it really required to write a procedure? Can't something like that do the trick:
SELECT OFFCD, GLHEAD, YEAR,
SUM(CASE WHEN MONTH <= 01 THEN AMOUNT ELSE 0 END) YTDBAL_1,
SUM(CASE WHEN MONTH <= 02 THEN AMOUNT ELSE 0 END) YTDBAL_2,
SUM(CASE WHEN MONTH <= 03 THEN AMOUNT ELSE 0 END) YTDBAL_3,
SUM(CASE WHEN MONTH <= 04 THEN AMOUNT ELSE 0 END) YTDBAL_4,
SUM(CASE WHEN MONTH <= 05 THEN AMOUNT ELSE 0 END) YTDBAL_5
-- and so on up to YTDBAL_12
-- ...
FROM A
GROUP BY OFFCD, GLHEAD, YEAR
Producing (given the first 8 rows of your sample data):
OFFCD GLHEAD YEAR YTDBAL_1 YTDBAL_2 YTDBAL_3 YTDBAL_4 YTDBAL_5
10 10101001 2014 30000 42000 52000 62000 61000

Related

sqlite multiple query conditions

I've searched but can't find the right answer, and I'm going round in circles.
I have
CREATE TABLE History (yr Int, output Int, cat Text);
yr output cat
---------- ---------- ----------
2015 10 a
2016 20 a
2017 30 a
2018 50 a
2019 70 a
2015 100 b
2016 200 b
2017 300 b
2018 500 b
2019 700 b
2015 1000 c
2016 2000 c
2017 3000 c
2018 5000 c
2019 7000 c
2015 10000 d
2016 20000 d
2017 30000 d
2018 50000 d
2019 70000 d
I've created two views
CREATE VIEW Core AS select * from History where cat = "c" or cat = "d";
CREATE VIEW Plus AS select * from History where cat = "a" or cat = "b";
My query is
select distinct yr, sum(output), (select sum(output) from core group by yr) as _core, (select sum(output) from plus group by yr) as _plus from history group by yr;
yr sum(output) _core _plus
---------- ----------- ---------- ----------
2015 11110 11000 110
2016 22220 11000 110
2017 33330 11000 110
2018 55550 11000 110
2019 77770 11000 110
Each of the individual queries works but _core and _plus columns are wrong when it's all put together. How should I approach this please.
You may generate your expected output without a view, using a single query with conditional aggregation:
SELECT
yr,
SUM(output) AS sum_output,
SUM(CASE WHEN cat IN ('c', 'd') THEN output ELSE 0 END) AS _core,
SUM(CASE WHEN cat IN ('a', 'b') THEN output ELSE 0 END) AS _plus
FROM History
GROUP BY
yr;
If you really wanted to make your current approach work, one way would be to just join the two views by year. But that would leave open the possibility that each view might not have every year present.

last 6 months total in Teradata

I have to calculate total quantity sold for last 6 months. For example in case of January 2018 , I have to calculate told quantity sold from July - Dec 2017. This total should be grouped by primary key.
Thanks
Primary Key Date qty last 6 months quantity sold
1 1-Oct 4 0
1 1-Nov 10 4
1 5-Dec 20 14
1 1-Jan 3 34
1 1-Sep 88 0
You can calculate the range using ADD_MONTHS plus TRUNC:
WHERE datecole BETWEEN Trunc(Add_Months(Current_Date, -6), 'mon')
AND Trunc(Current_Date, 'mon') -1

Month Calculate every 28 Days

is there any way in Oracle that My month start after every 28 days
Example
24-dec- 2015 to 20-jan-16 ( we mention Dec 2015)
21-jan-16 to 17-feb-16 (we mention Jan 16)
select rownum as month_number
,day1 + (rownum-1) * 28 as gregorian_month_start
,day1 + rownum * 28 - 1 as gregorian_month_end
from (select date'2015-12-24' day1
from dual connect by level <= 13);
1 24/DEC/2015 20/JAN/2016
2 21/JAN/2016 17/FEB/2016
3 18/FEB/2016 16/MAR/2016
4 17/MAR/2016 13/APR/2016
5 14/APR/2016 11/MAY/2016
6 12/MAY/2016 08/JUN/2016
7 09/JUN/2016 06/JUL/2016
8 07/JUL/2016 03/AUG/2016
9 04/AUG/2016 31/AUG/2016
10 01/SEP/2016 28/SEP/2016
11 29/SEP/2016 26/OCT/2016
12 27/OCT/2016 23/NOV/2016
13 24/NOV/2016 21/DEC/2016
Note: this doesn't handle the 365th day for normal years, or 366th day for leap years. You would need to specify which month these should be added to.

Query formatting

I have table with below rows
Name Month Salary Expense
John Jan 1000 50
John Feb 5000 2000
Jack Jan 3000 100
I want to get output in the below format. How to achieve this.
Name JAN FEB
John 1000 50 5000 2000
Jack 3000 100 0 0
This sql(-server) query would work:
select name,
isnull(max(case when month='jan' then salary end), 0) as Salary_jan,
isnull(max(case when month='feb' then salary end), 0) as Salary_feb
-- and so on
group by name

get entire row with MAX() on several columns

first off: thanks for looking; your time is appreciated!
to the point:
SCHEMA: for myTable
nonUniqueID YEAR MONTH DAY HOUR numericValue
1 2012 01 01 01 99.9
1 2012 01 01 02 65.2
1 2012 01 01 03 -88
7 2012 02 08 21 9.08
1 2012 01 01 09 99.913
1 2013 01 01 01 99.999999
Basically, it's two values nonUniqueID and numericValue with a granular date.
Now, i need to get the single greatest date in this entire database. With the data above, the expected result would be:
nonUniqueID YEAR MONTH DAY HOUR numericValue
1 2013 01 01 01 99.999999
Because this is SQLite, i know that i will end up having to use MAX() several times. The order will have to be MAX(YEAR) then MAX(MONTH) then MAX(DAY) then MAX(HOUR).
Basically, the query would work like this (i just don't know enough about SQL syntax to create the query):
Find all records with highest YEAR
From this set, find all records with highest MONTH
From this set, find all records with highest DAY
From this set, find all records with highest HOUR
return this record
Here is a SQL that i adapted from another StackExchange question that does not work
Select * From (
Select max(YEAR) as Y FROM myTable
union
Select max(MONTH) as M FROM myTable
union
Select max(DAY) as D FROM myTable
union
Select max(HOUR) as H FROM myTable
) myTable;
which returns
Y
-----
21
08
02
2013
Compare this to expected out:
nonUniqueID YEAR MONTH DAY HOUR numericValue
1 2013 01 01 01 99.999999
it returned 4 records instead of the one record with the 4 values.
Can somebody please help me with my query? THANK YOU!
Try this
SELECT nonUniqueID , YEAR , MONTH , DAY , HOUR , numericValue FROM myTable as a
INNER JOIN (Select max(MONTH) FROM myTable) as b
ON a.YEAR = B.YEAR
INNER JOIN (Select max(DAY) FROM myTable) as c
ON b.YEAR = c.YEAR
INNER JOIN (Select max(HOUR) FROM myTable) as d
ON c.YEAR = d.YEAR
WHERE a.YEAR = (Select max(YEAR) FROM myTable)
It returns 4 values because you use UNION
it means that the result are join in one column
EDIT
Ive just updated my answer see if that works Im not quite sure to the performance of this query

Resources