how to update column with previous data - sql

how to get previous record depend on unique_id and date?
i want make my table (dbo : Daily_Summary) :
ID Partner part_no Date Periode_Sum Previous_Sum
1 aa 12 2011-12-21 40
2 aa 12 2011-12-22 30 40
3 bb2 13 2011-12-22 20
4 bb2 13 2011-12-23 30 20
5 2011-12-24
6 2011-12-25
7 aa 12 2011-12-26 30 70
8 bb2 13 2011-12-27 40 50
and so on
which 'Previous_Sum' is function update, and the function only update the previous record of Periode_Sum. And group by partner, part_no and date
My display query had error to.
When i display the previous record by partner, part_no and date. the record of previous_sum only displayed the first partner.
here is my query :
SELECT ds.partner_id, ds.part_no, ds. periode_in
, ds.periode_out, ds.periode_date, ds.periode_sum,
(
SELECT F1.periode_sum
FROM Daily_Summary as F1 where
F1.periode_sum =
(
SELECT Max(F2.periode_sum)
FROM Daily_Summary as F2 where F2.periode_date < ds.periode_date
and F2.partner_id=ds.partner_id and F2.part_no = ds.part_no
)
) AS Prev_Value
FROM Daily_Summary ds
where stsrc='A'
order by ds.partner_id, ds.periode_date
i tried using declare new param but not working :
DECLARE #prev_sum INT = 0
DECLARE #dudut INT = 2
SELECT #prev_sum =
(select sum(periode_sum)
from Daily_Summary t1
where t1.partner_id = ds.partner_id and t1.part_no = ds.part_no
and t1.periode_date < ds.periode_date --and t1.id < t.id
)
FROM Daily_Summary ds
where stsrc='A'
order by ds.partner_id, ds.periode_date
select partner_id,part_no,model,periode_sum,
case when #prev_sum is null then #dudut else #prev_sum end
FROM daily_summary
where stsrc='A'

select * into #tab from (
select 1 as id, 'aa' as partner, 12 as part_no,
cast('2011-12-21' as datetime) as date, 40 as periode_sum union all
select 2, 'aa', 12, '2011-12-22', 30 union all
select 3, 'bb2', 13, '2011-12-22', 20 union all
select 4, 'bb2', 13, '2011-12-23', 30 union all
select 5, null, null, '2011-12-24', null union all
select 6, null, null, '2011-12-25', null union all
select 7, 'aa', 12, '2011-12-26', 30 union all
select 8, 'bb2', 13, '2011-12-27', 40
) t
select *, (select sum(periode_sum)
from #tab t1
where t1.partner = t.partner and t1.part_no = t.part_no
and t1.date < t.date and t1.id < t.id
) as previous_sum
from #tab t
If more than one row per day for specific pair (partner, part_no) is allowed then instead of and t1.date < t.date and t1.id < t.id you should use and t1.date <= t.date and t1.id < t.id. You can use just and t1.id < t.id if id ensures proper order (in time) for all rows.
Result:
id partner part_no date periode_sum previous_sum
1 aa 12 2011-12-21 00:00:00.000 40 NULL
2 aa 12 2011-12-22 00:00:00.000 30 40
3 bb2 13 2011-12-22 00:00:00.000 20 NULL
4 bb2 13 2011-12-23 00:00:00.000 30 20
5 NULL NULL 2011-12-24 00:00:00.000 NULL NULL
6 NULL NULL 2011-12-25 00:00:00.000 NULL NULL
7 aa 12 2011-12-26 00:00:00.000 30 70
8 bb2 13 2011-12-27 00:00:00.000 40 50

Related

How to calculate new column with sum of moving time window within a group in snwoflake SQL?

I have a table like this:
date
ID
count
2021-01-01
A
24
2021-01-02
A
10
2021-01-03
A
5
2021-01-04
A
1
2021-01-01
B
5
2021-01-02
B
10
2021-01-03
B
1
2021-01-04
B
10
2021-01-01
C
5
2021-01-03
C
10
2021-01-04
C
1
2021-01-05
C
10
and I want to calculate a new column that sums the count value for the two days before the date within each ID. There might be missing dates (days) in between, which is why a simple lag function propably will not work (See example ID C). So I want to sum the values in between a certain date range within each ID.
So the resulting table should look like
date
ID
count
sum_two_days_before
2021-01-01
A
24
Null
2021-01-02
A
10
Null
2021-01-03
A
5
34
2021-01-04
A
1
15
2021-01-01
B
5
Null
2021-01-02
B
10
Null
2021-01-03
B
1
15
2021-01-04
B
10
11
2021-01-01
C
5
Null
2021-01-03
C
10
5
2021-01-04
C
1
10
2021-01-05
C
10
11
Would be glad about help!
A correlated sub-query might work.
But can't verify.
SELECT *
, ( SELECT SUM(t2.count)
FROM your_table t2
WHERE t2.ID = t.ID
AND t2.date IN (DATEADD(day,-1,t.date), DATEADD(day,-2,t.date))
HAVING COUNT(t2.date) = 2
) AS sum_two_days_before
FROM your_table t
ORDER BY t.ID, t.date;
And if that doesn't work.
Maybe adding 2 LAG will work.
But it just looks for previous days, not today-1 & today-2
SELECT *
, LAG(t.count, 1) OVER (PARTITION BY t.ID ORDER BY t.date) +
LAG(t.count, 2) OVER (PARTITION BY t.ID ORDER BY t.date) AS sum_two_dates_before
FROM your_table t
ORDER BY t.ID, t.date;
But if snowlake isn't having the HAVING, then maybe this will work.
SELECT *
, ( SELECT
SUM(CASE WHEN t.date = DATEADD(day,-2,t.date) THEN t2.count END)
+ SUM(CASE WHEN t.date = DATEADD(day,-1,t.date) THEN t2.count END)
FROM your_table t2
WHERE t2.ID = t.ID
AND t2.date IN (DATEADD(day,-1,t.date), DATEADD(day,-2,t.date))
) AS sum_two_days_before
FROM your_table t
ORDER BY t.ID, t.date;
So correct "as described" results can be gotten from a verbose version:
WITH data AS (
SELECT * FROM values
('2021-01-01','A', 24, null),
('2021-01-02','A', 10, null),
('2021-01-03','A', 5, 34),
('2021-01-04','A', 1, 15),
('2021-01-01','B', 5, null),
('2021-01-02','B', 10, null),
('2021-01-03','B', 1, 15),
('2021-01-04','B', 10, 11),
('2021-01-01','C', 5, null),
('2021-01-03','C', 10, 5),
('2021-01-04','C', 1, 10),
('2021-01-05','C', 10, 11)
v(date, id, count, expected )
)
SELECT
date,
id,
count,
expected,
sum_2_days
FROM (
SELECT
date,
id,
count,
expected,
LAG(date,2)over(partition by id order by date) as d2,
LAG(date,1)over(partition by id order by date) as d1,
lag(count,2)over(partition by id order by date) as c2,
lag(count,1)over(partition by id order by date) as c1,
dateadd(day,-2,date)::date AS dm2,
d2 is not null OR d1 = dm2 as X1,
iff(d2 >= dm2, c2, 0) as x1_v2,
iff(d1 >= dm2, c1, 0) as x1_v1,
x1_v2 + x1_v1 as x1_r,
iff(X1, x1_r, null) as sum_2_days
FROM data
)
order by 2,1;
giving:
DATE
ID
COUNT
EXPECTED
SUM_2_DAYS
2021-01-01
A
24
2021-01-02
A
10
2021-01-03
A
5
34
34
2021-01-04
A
1
15
15
2021-01-01
B
5
2021-01-02
B
10
2021-01-03
B
1
15
15
2021-01-04
B
10
11
11
2021-01-01
C
5
2021-01-03
C
10
5
5
2021-01-04
C
1
10
10
2021-01-05
C
10
11
11
or the compressed version:
SELECT
date,
id,
count,
expected,
iff( LAG(date,2)over(partition by id order by date) is not null
OR LAG(date,1)over(partition by id order by date) = dateadd(day,-2,date)
, iff( LAG(date,2)over(partition by id order by date) >= dateadd(day,-2,date)
,lag(count,2)over(partition by id order by date)
,0)
+ iff( LAG(date,1)over(partition by id order by date) >= dateadd(day,-2,date)
,lag(count,1)over(partition by id order by date)
,0)
,null) as sum_2_days
FROM data
order by 2,1;
AND if you really want to do it with a double join you can via some pre-conditioning:
WITH date_a AS (
SELECT date, id, count, expected,
dateadd(day,-2,date) as dm2,
first_value(date)over(partition by id order by date) as fd
FROM data
)
select
a.date,
a.id,
a.count,
a.expected,
sum(iff(a.fd <= a.dm2, b.count, null)) as sum_2_days
FROM date_a a
LEFT JOIN data b
ON a.id = b.id AND a.date > b.date AND b.date >= a.dm2
GROUP BY 1,2,3,4
order by 2,1;

Fill in gaps in year sequence in SQL Server

I have a table with the columns Age, Period and Year. The column Age always starts with 0 and doesn't have a fixed maximum value (I used 'Age' 0 to 30 in this example but the range could also be 0 to 100 etc.), the values Period and Year only appear in certain rows at certain ages.
However at what Age the values for Period and Year appear, changes and the solution should therefore be dynamic. What is the best way to fill in the NULL values with correct Period and Year?
I am using SQL Server.
Age Period Year
-----------------
0 NULL NULL
1 NULL NULL
2 NULL NULL
3 NULL NULL
4 NULL NULL
5 NULL NULL
6 NULL NULL
7 NULL NULL
8 NULL NULL
9 NULL NULL
10 NULL NULL
11 NULL NULL
12 NULL NULL
13 NULL NULL
14 NULL NULL
15 NULL NULL
16 NULL NULL
17 NULL NULL
18 NULL NULL
19 NULL NULL
20 NULL NULL
21 46 2065
22 NULL NULL
23 NULL NULL
24 NULL NULL
25 NULL NULL
26 51 2070
27 NULL NULL
28 NULL NULL
29 NULL NULL
30 NULL NULL
The result should look like this, the numbers for Period and Year should be increased and/or decrease from the last known values for Period and Year.
Age Period Year
-----------------
0 25 2044
1 26 2045
2 27 2046
3 28 2047
4 29 2048
5 30 2049
6 31 2050
7 32 2051
8 33 2052
9 34 2053
10 35 2054
11 36 2055
12 37 2056
13 38 2057
14 39 2058
15 40 2059
16 41 2060
17 42 2061
18 43 2062
19 44 2063
20 45 2064
21 46 2065
22 47 2066
23 48 2067
24 49 2068
25 50 2069
26 51 2070
27 52 2071
28 53 2072
29 54 2073
30 55 2074
Here is an UPDATE to my question as I didn't specify my requirement detailed enough:
The solution should be able to handle different combinations of Age, Period and Year. My start point will always be a known Age, Period and Year combination. However, the combination Age = 21, Period = 46 and Year = 2065 (or 26|51|2070 as the second combination) in my example is not static. The value at Age = 21 could be anything e.g. Period = 2 and Year = 2021. Whatever the combination (Age, Period, Year) is, the solution should fill in the gaps and finish the sequence counting up and down from the known values for Period and Year. If a Period value sequence becomes negative the solutions should return NULL values, if possible.
Seem you have always the same increment for age and year
so
select age, isnull(period,age +25) Period, isnull(year,age+44) year
from yourtable
or the standard function coalesce (as suggested by Gordon Linoff)
select age, coalesce(period,age +25) Period, coalesce(year,age+44) year
from yourtable
Tabel creation code
create table yourtable ( AGE int , Period int, Year int )
insert into yourtable
Select 0 AS AGE , null As Period , null As Year UNION all
Select 1 AS AGE , null As Period , null As Year UNION all
Select 2 AS AGE , null As Period , null As Year UNION all
Select 3 AS AGE , null As Period , null As Year UNION all
Select 4 AS AGE , null As Period , null As Year UNION all
Select 5 AS AGE , null As Period , null As Year UNION all
Select 6 AS AGE , null As Period , null As Year UNION all
Select 7 AS AGE , null As Period , null As Year UNION all
Select 8 AS AGE , null As Period , null As Year UNION all
Select 9 AS AGE , null As Period , null As Year UNION all
Select 10 AS AGE , null As Period , null As Year UNION all
Select 11 AS AGE , null As Period , null As Year UNION all
Select 12 AS AGE , null As Period , null As Year UNION all
Select 13 AS AGE , null As Period , null As Year UNION all
Select 14 AS AGE , null As Period , null As Year UNION all
Select 15 AS AGE , null As Period , null As Year UNION all
Select 16 AS AGE , null As Period , null As Year UNION all
Select 17 AS AGE , null As Period , null As Year UNION all
Select 18 AS AGE , null As Period , null As Year UNION all
Select 19 AS AGE , null As Period , null As Year UNION all
Select 20 AS AGE , null As Period , null As Year UNION all
Select 21 AS AGE ,46 As Period ,2065 As Year UNION all
Select 22 AS AGE , null As Period , null As Year UNION all
Select 23 AS AGE , null As Period , null As Year UNION all
Select 24 AS AGE , null As Period , null As Year UNION all
Select 25 AS AGE , 51 As Period ,2070 As Year UNION all
Select 26 AS AGE , null As Period , null As Year UNION all
Select 27 AS AGE , null As Period , null As Year UNION all
Select 28 AS AGE , null As Period , null As Year UNION all
Select 29 AS AGE , null As Period , null As Year UNION all
Select 30 AS AGE , null As Period , null As Year
**Steps **
We need to get one row with non null value for Period and year.
Using age get first value for both the column .
Now just add respective age column value and fill full table .
Code to fix the serial
;with tmp as
(select top 1 * from yourtable where Period is not null and year is not null)
update yourtable
set Period = (tmp.Period - tmp.age) + yourtable.age
, year = (tmp.year - tmp.age) + yourtable.age
from yourtable , tmp
OR
Declare #age int ,#Year int ,#Period int
select #age = age , #Year = year - (age +1) ,#Period = Period- (AGE +1)
from yourtable where Period is not null and year is not null
update yourtable
set Period =#Period + age
,Year =#year + age
from yourtable
You finally want three sequences with different start values. Then you simply need to calculate an offset and add it to age:
with cte as
(
select age
,max(period - age) over () + age as period -- adjusted period
,max(yr - age) over () + age as yr -- adjusted yr
from #yourtable
)
select age
-- If a Period value sequence becomes negative the solutions should return NULL
,case when period >0 then period end as period
,yr
from cte
See fiddle
-- hope you can manage the syntax error. but some logic like given below should work in this case where we can make period an origin to calculate other missing values. good luck!
declare #knownperiod int;
declare #knownperiodage int;
declare #agetop int;
declare #agebottom int;
#knownperiod = select top 1 period from table1 where period is not null
#knownperiodage = select top 1 age from table1 where period is not null
while(#knownperiodage >= 0)
begin
#knownperiod = #knownperiod -1 ;
#knownperiodage = #knownperiodage -1;
update table1 set period = #knownperiod, year = YEAR(GetDate())+#knownperiod-1 where age = #knownperiodage
end
-- now for bottom age
#knownperiod = select top 1 period from table1 where period is null or year is null
#knownperiodage = select top 1 age from table1 where period is null or year is null
while(#knownperiodage <= (Select max(age) from table1))
begin
#knownperiod = #knownperiod +1 ;
#knownperiodage = #knownperiodage +1;
update table1 set period = #knownperiod, year = YEAR(GetDate())+#knownperiod-1 where age = #knownperiodage
end
Is the process to first calculate the increments (age -> period and age -> year) then simply add those increments to the age values?
This assumes the differences between age and period, and age and year, are consistent across rows (just not filled in sometimes).
As such, you could use the following to first calculate the increments (PeriodInc, YrInc) and then select the values with the increments added (noting that if period goes negative, it gets NULL).
; WITH PeriodInc AS (SELECT TOP 1 Period - Age AS PeriodInc FROM #yourtable WHERE Period IS NOT NULL),
YrInc AS (SELECT TOP 1 Yr - Age AS YrInc FROM #yourtable WHERE Yr IS NOT NULL)
SELECT Age,
CASE WHEN (Age + PeriodInc) >= 0 THEN (Age + PeriodInc) ELSE NULL END AS Period,
Age + YrInc AS Yr
FROM #yourtable
CROSS JOIN PeriodInc
CROSS JOIN YrInc
Here is a DB_Fiddle with the code
This solution takes 4 inputs:
#list_length -- (integer) the number of rows to generate (up to 12^5=248,832)
#start_age -- (integer) beginning age
#start_period -- (integer) beginning period
#start_year -- (integer) beginning year
For any combination of inputs this code generates the requested output. If either the Age or Year is calculated to be negative then it is converted to NULL. The current limit to the list length could be increased to whatever is necessary. The technique of creating a row_number using cross applied rows is known to be very fast when generating large sequences. Above about 500 rows it's always faster than a recursion based CTE. At small row numbers there's little to no performance difference between the two techniques.
Here are the code and output to match the example data.
Inputs
declare
#list_length int=31,
#start_age int=21,
#start_period int=46,
#start_year int=2065;
Code
with
n(n) as (select * from (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) v(n)),
tally_cte(n) as (
select row_number() over (order by (select null))
from n n1 cross join n n2 cross join n n3 cross join n n4 cross join n n5)
select p.Age,
case when p.[Period]<0 then null else p.[Period] end [Period],
case when p.[Year]<0 then null else p.[Year] end [Year]
from tally_cte t
cross apply
(select (t.n-1) [Age], (t.n-1)+(#start_period-#start_age) [Period],
(t.n-1)+(#start_year-#start_age) [Year]) p
where n<=#list_length;
Output
Age Period Year
0 25 2044
1 26 2045
2 27 2046
3 28 2047
4 29 2048
5 30 2049
6 31 2050
7 32 2051
8 33 2052
9 34 2053
10 35 2054
11 36 2055
12 37 2056
13 38 2057
14 39 2058
15 40 2059
16 41 2060
17 42 2061
18 43 2062
19 44 2063
20 45 2064
21 46 2065
22 47 2066
23 48 2067
24 49 2068
25 50 2069
26 51 2070
27 52 2071
28 53 2072
29 54 2073
30 55 2074
Suppose both the Period and the Year are less than the start Age. When the calculated values are negative the value is replaced with a NULL.
Inputs
declare
#list_length int=100,
#start_age int=10,
#start_period int=5,
#start_year int=8;
Output
Age Period Year
0 NULL NULL
1 NULL NULL
2 NULL 0
3 NULL 1
4 NULL 2
5 0 3
6 1 4
7 2 5
8 3 6
9 4 7
10 5 8
11 6 9
12 7 10
...
99 94 97
Imo this is a flexible and efficient way to meet all of the requirements. Please let me know if there are any issues.
This reads like a gaps-and-islands problem, where "empty" rows are the gaps and non-empty rows are the islands.
You want to fill the gaps. Your question is a bit tricky, because you do not clearly describe how to proceed when a gap row has both preceding and following islands - and what to do if they are not consistent.
Let me assume that you want to derive the value from the following island if there is one available, and fall back of the precedng island.
Here is an approach using lateral joins to retrieve the next and preceding non-empty row:
select t.age,
coalesce(t.period, n.period - n.diff, p.period - p.diff) period,
coalesce(t.year, n.year - n.diff, p.year - p.diff) year
from mytable t
outer apply (
select top (1) t1.*, t1.age - t.age diff
from mytable t1
where t1.age > t.age and t1.period is not null and t1.year is not null
order by t1.age
) n
outer apply (
select top (1) t1.*, t1.age - t.age diff
from mytable t1
where t1.age < t.age and t1.period is not null and t1.year is not null
order by t1.age desc
) p
order by t.age
Actually, this would probably be more efficiently performed with window functions. We can implement the very same logic by building groups of records with window counts, then doing the computation within the groups:
select
age,
coalesce(
period,
max(period) over(partition by grp2) - max(age) over(partition by grp2) + age,
max(period) over(partition by grp1) - min(age) over(partition by grp1) + age
) period,
coalesce(
year,
max(year) over(partition by grp2) - max(age) over(partition by grp2) + age,
max(year) over(partition by grp1) - min(age) over(partition by grp1) + age
) year
from (
select t.*,
count(period) over(order by age) grp1,
count(period) over(order by age desc) grp2
from mytable t
) t
order by age
Demo on DB Fiddle - both queries yield:
age | period | year
--: | -----: | ---:
0 | 25 | 2044
1 | 26 | 2045
2 | 27 | 2046
3 | 28 | 2047
4 | 29 | 2048
5 | 30 | 2049
6 | 31 | 2050
7 | 32 | 2051
8 | 33 | 2052
9 | 34 | 2053
10 | 35 | 2054
11 | 36 | 2055
12 | 37 | 2056
13 | 38 | 2057
14 | 39 | 2058
15 | 40 | 2059
16 | 41 | 2060
17 | 42 | 2061
18 | 43 | 2062
19 | 44 | 2063
20 | 45 | 2064
21 | 46 | 2065
22 | 47 | 2066
23 | 48 | 2067
24 | 49 | 2068
25 | 50 | 2069
26 | 51 | 2070
27 | 52 | 2071
28 | 53 | 2072
29 | 54 | 2073
30 | 55 | 2074
Also you can use recursive CTE (it can handle any variation of data in the table except only one that has no populated period and year at all):
WITH cte AS ( -- get any filled period and year
SELECT TOP 1 period - age delta,
[year]-period start_year
FROM tablename
WHERE period is not null and [year] is not null
), seq AS ( --get min and max age values
SELECT MIN(age) as min_age, MAX(age) as max_age
FROM tablename
), go_recursive AS (
SELECT min_age age,
min_age+delta period ,
start_year+min_age+delta year,
max_age
FROM seq
CROSS JOIN cte --That will generate the initial first row
UNION ALL
SELECT age + 1,
period +1,
year + 1,
max_age
FROM go_recursive
WHERE age < max_age --This part increments the data from first row
)
SELECT age,
period,
[year]
FROM go_recursive
OPTION (MAXRECURSION 0)
-- If you know there are some limit of rows in that kind of tables
--use this row count instead 0

Find out average loan taken by age group in specific ranges and display them in a table

Consider the following 2 tables:
customer( **c_id**, c_name, c_dob)
customer_loan_taken( **loan_no**, c_id, taken_date, loan_amount)
How to find out average loan taken by age group 20-25, 30-35, 40-45, and display them in a single table ?
The table contents are as follows:
customer table
C_ID C_NAME C_DOB
1 Jainam Jhaveri 17-FEB-93
2 Harsh Mehra 10-DEC-91
3 Mohit Desai 15-OCT-75
4 Raj Gupta 31-AUG-80
5 Yash Shah 24-NOV-85
6 Dishank Parikh 02-OCT-78
7 Chandni Jain 06-MAR-83
8 Bhavesh Prajapati 13-MAY-71
9 Priyank Khandelwal 18-JUN-86
10 Mihir Vora 11-NOV-95
customer_loan_taken table
LOAN_NO C_ID TAKEN_DAT LOAN_AMOUNT
1011 1 12-SEP-11 100000
1012 3 20-APR-10 200010
1013 4 15-OCT-12 150000
1014 5 04-JAN-13 2500005
1015 7 15-AUG-16 2600001
1016 8 21-DEC-16 3500000
1017 9 13-NOV-17 4000000
1018 10 05-MAR-18 1010100
This is working in Oracle 12c. The trick to figure out the age can differ on database as datediff is not working in oracle. So modify it accordingly
with customer( c_id, c_name, c_dob) as
(select 1,'A','31/01/1990' from dual union
select 2,'A','31/01/1980' from dual union
select 3,'C','31/01/1970' from dual union
select 4,'D','31/08/1990' from dual),
ag as
(select c.* ,
FLOOR(TRUNC(MONTHS_BETWEEN(SYSDATE, to_date(c_dob,'DD/MM/YYYY'))) /12) as age,
case when FLOOR(TRUNC(MONTHS_BETWEEN(SYSDATE, to_date(c_dob,'DD/MM/YYYY'))) /12) between 20 and 25 then '20-25' when
FLOOR(TRUNC(MONTHS_BETWEEN(SYSDATE, to_date(c_dob,'DD/MM/YYYY'))) /12) between 30 and 35 then '30-35' when
FLOOR(TRUNC(MONTHS_BETWEEN(SYSDATE, to_date(c_dob,'DD/MM/YYYY'))) /12) between 40 and 45 then '40-45'
end as agegroup from customer c
),
customer_loan_taken( loan_no, c_id, taken_date, loan_amount)
as
(
select 101,1,'01/01/1990',1000 from dual union
select 102,2,'01/01/1990',2000 from dual union
select 103,3,'01/01/1990',3000 from dual union
select 104,4,'01/01/1990',4000 from dual
)
select distinct(ag.agegroup),avg(loan_amount) from customer_loan_taken cl,ag
where ag.c_id=cl.c_id
group by ag.agegroup
;WITH cte AS (
SELECT CASE
WHEN DATEDIFF ("YY", c_dob, GETDATE()) > 20
AND DATEDIFF ("YY", c_dob, GETDATE()) <= 25 THEN '20-25'
WHEN DATEDIFF ("YY", c_dob, GETDATE()) > 25
AND DATEDIFF ("YY", c_dob, GETDATE()) <= 30 THEN '25-30'
WHEN DATEDIFF ("YY", c_dob, GETDATE()) > 30
AND DATEDIFF ("YY", c_dob, GETDATE()) <= 35 THEN '30-35'
END AS rangedate,
l.loan_amount
FROM customer
INNER JOIN customer_loan_taken l ON customer.c_id = l.c_id
)
SELECT rangedate,
AVG(loan_amount) average
FROM cte
GROUP BY rangedate
select avg(loan_amt) "LOAN_AVG",age_range from(
select l.loan_amount as loan_amt,
(case
when FLOOR((months_between(sysdate,to_CHAR(c.c_dob,'DD-MON-YYYY')))/12)
between 20 and 25 then '20-25'
when FLOOR((months_between(sysdate,to_CHAR(c.c_dob,'DD-MON-YYYY')))/12)
between 30 and 35 then '30-35'
when FLOOR((months_between(sysdate,to_CHAR(c.c_dob,'DD-MON-YYYY')))/12)
between 40 and 45 then '40-45'
else '46-90'
end) as age_range
from customer c,cust_loan_taken l
where c.C_ID=l.C_ID) a
group by age_range;

Cumulative result of items for drawing

I have a table ENG_Drawing.Its fields are
SELECT DrawingID,DrawingNumber,DrawingDescription FROM ENG_Drawing
DrawingID DrawingNumber DrawingDescription etc..
1131 R152-14-01-00-31 DU - 01 etc..
....
1200 R160-02-01-00-21 DU - 12 etc..
....
.....
....
1500 R156-01-01-00-11 DU - 00 etc..
....
.....
2993 R167-09-01-00-21 DU - 04 etc..
2994 R165-10-01-00-40 DU - 25 etc..
2995 R163-13-01-00-01 DU - 24 etc..
2996 R100-12-01-00-61 DU - 21 etc..
2997 R166-09-01-00-21 DU - 21 etc..
2998 R125-14-01-00-02 DU - 32 etc..
2999
3000
.
.
And detail table for drawing table is
DrawingID SeqNbr Drawing_f BOMQuantity ItemQty DrawingreferenceID ItemID
1131 7 0 2 0.574 1231
1131 9 1 4 null 1200 null
....
....
1200 14 1 8 0.560 1100 1555
1200 16 1 2 5.23 1500 1755
....
....
1500 18 0 2 4.350 2684
....
2993 5 0 2 0.061 2125
2993 6 0 2 1.592 1698
2993 7 0 2 2.500 1231
2993 9 1 4 null 1131 null
2993 16 1 2 null 1500 null
2993 18 0 2 4.350 2684
When I give DrawingID as 2993
In need output like this
ITEMID TOTALQTY
1231 9.592 //select((2*2.500) + (4*2*.574)) here (2*2.500)- is BOMQuantity(4)*ItemQty(2.500) for ItemID 2993 and (4*2*.574)- BOMQuantity of DrawingID 1131(4)*BOMQuantity of ItemID 1231 in DRawingID 1131(2)*ItemQty(.574)
1555 71.680 //select(4*4*8*.560) here 4-BOMQuantity of DrawingreferenceID 1131 in DrawingID 2993.Middle 4 is BOMQuantity of DrawingreferenceID 1200 in DrawingID 1131. 8 is BOMQuantity of ItemId 1555 in DrawingId 1200
1698 3.184 //select(2*1.592)
1755 50.944 //select(4*4*2*1.592)
2125 0.122 //select(2*0.061)
2684 0.122 //select((2*4.350)+(2*2*4.350))
ENG_Drawing_BOM contains subdrawings (DrawingreferenceID).they(DrawingreferenceID) have their values in ENG_Drawing table and also have items and subdrawings.
One drawing may have no of subdrawings and that subdrawings can have subdrawings and so on....
I need When i give DrawingID i need Item wise cumulation.The result should be is ITEMID,sum( BOMQuantity * ItemQty) as TOTALQTY.
The problem is,
For exmple
DrawingID has subdrawing with 4 BOMQuantity, i need TOTALQTY 4 times of that subdrawing(S1) items,
if that subdrawing has subdrawings(S2) with 6 BOMQuantity need 4 times of S1 items and 4*6 4 times of S2 items ...It will continue for its inner levels...
I finally need Overall ITEMID wise cumulation
here 2993 as main drawing.1131,1200,1500 are subdrawings and that subdrawings may have sub drawings.I need them also .
Any body????
#Suresh recheck your sample data,what is wrong in my query ?
Declare #drawing table( DrawingID int,SeqNbr int,Drawing_f int,BOMQuantity decimal(5,2),ItemQty decimal(6,3),DrawingreferenceID int,ItemID int)
insert into #drawing
select 1131 , 7, 0,2, 0.574,null,1231 union all
select 1131 , 9, 1,4,null ,1200,null union all
select 1200, 14, 1,8,0.560, 1100,1555 union all
select 1200, 16, 1,2,5.23 , 1500,1755 union all
select 1500, 18, 0,2,4.350, null,2684 union all
select 2993, 5, 0,2,0.061, null,2125 union all
select 2993, 6, 0,2,1.592, null,1698 union all
select 2993, 7, 0,2,2.500, null,1231 union all
select 2993, 9, 1,4,null , 1131,null union all
select 2993, 16, 1,2,null , 1500,null union all
select 2993, 18, 0 ,2,4.350, null,2684
--select * from #drawing
;with cte as
(select * ,1 roots from #drawing where DrawingID=2993
union all
select d.*,case when d.DrawingID=c.DrawingreferenceID then roots+1 else roots end from #drawing d inner join cte c on d.DrawingID=c.DrawingreferenceID
)
select * from cte
#Suresh if your last query is ok then make it accurate
with cte as
(
select d.* , 1 as Nooff,1 roots,d.DrawingID as 'MainDrawing' from ENG_Drawing_BOM d
union all
select d.*,c.BOMQuantity*C.Nooff as Nooff,case when d.DrawingID=c.DrawingreferenceID then roots+1 else roots end ,MainDrawing as 'MainDrawing'
from ENG_Drawing_BOM d inner join cte c on d.DrawingID=c.DrawingreferenceID
)
,CTE1 as
(
select
cte.MainDrawing,
cte.ItemID,
SUM(Nooff*cte.UnitWeight)as 'Wt',
SUM((TotalQty)*Nooff) as 'TotalQty'
from cte
where DrawingReferenceID is null AND MainDrawing = 2993
group by cte.ItemID, cte.MainDrawing
)
select
cte.MainDrawing,
cte.ItemID,
i.ItemDescription,
Wt,
TotalQty
from cte1
inner join STR_Item i on cte.ItemID = i.ItemID
where DrawingReferenceID is null AND MainDrawing = 2993
ORDER BY cte.ItemID
This is exact need ...derived from KumarHarsh reply.
with cte as
(
select d.* , 1 as Nooff,1 roots,d.DrawingID as 'MainDrawing' from ENG_Drawing_BOM d
union all
select d.*,c.BOMQuantity*C.Nooff as Nooff,case when d.DrawingID=c.DrawingreferenceID then roots+1 else roots end ,MainDrawing as 'MainDrawing' from ENG_Drawing_BOM d inner join cte c on d.DrawingID=c.DrawingreferenceID
)
select
cte.MainDrawing,
cte.ItemID,
i.ItemDescription,
SUM(Nooff*cte.UnitWeight)as 'Wt',
SUM((TotalQty)*Nooff) as 'TotalQty'
from cte
inner join STR_Item i on cte.ItemID = i.ItemID
where DrawingReferenceID is null AND MainDrawing = 2993
group by cte.ItemID,
cte.MainDrawing,
i.ItemDescription
ORDER BY cte.ItemID

sql - max from group flag setter

I m trying to achieve flag setting for the condition in my table below
p_id mon_year e_id flag
---- --------- ----- -----
1 2011/11 20 0
1 2011/11 21 1
1 2012/01 22 1
1 2012/02 23 0
1 2012/02 24 0
1 2012/02 25 1
2 2011/11 28 0
2 2011/11 29 1
2 2012/01 30 1
grouping by p_id,e_id and mon_year, the flag is set for the last value in the month.
I m confused how can i achieve this
I tried to achieved this by using row_number and partition to seperate out the value. By still looking for to achieved
Output by using row_number query , i have got is as below:
Grouping by
p_id mon_year e_id row
---- --------- ----- -----
1 2011/11 20 1
1 2011/11 21 2
1 2012/01 22 1
1 2012/02 23 1
1 2012/02 24 2
1 2012/02 25 3
2 2011/11 28 1
2 2011/11 29 2
2 2012/01 30 1
Max of this value would set the flag column. But i m really bugged how to achieve it. Any help would be useful.
Thanks !!
I think this is what you're going for. . . The output exactly matches your example:
declare #t table (p_id int, [year] int, [month] int, [day] int)
insert #t select 1, 2011, 11, 20
union select 1, 2011, 11, 21
union select 1, 2012, 01, 22
union select 1, 2012, 02, 23
union select 1, 2012, 02, 24
union select 1, 2012, 02, 25
union select 2, 2011, 11, 28
union select 2, 2011, 11, 29
union select 2, 2012, 01, 30
select p_id, [year], [month], [day]
, case when r=1 then 1 else 0 end flag
from
(
select p_id, [year], [month], [day]
, row_number() over (partition by p_id, [year], [month] order by [day] desc) r
from #t
) x
order by p_id, [year], [month], [day]
Output:
p_id year month day flag
1 2011 11 20 0
1 2011 11 21 1
1 2012 1 22 1
1 2012 2 23 0
1 2012 2 24 0
1 2012 2 25 1
2 2011 11 28 0
2 2011 11 29 1
2 2012 1 30 1
Try ordering by descending. In that way, you don't have to look for maximum ROW_NUMBER but when ROW_NUMBER is 1 ;)
Something like this (I didn't completely understand what you want to achieve, so this is probably not 100% accurate):
WITH r_MyTable
AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY mon_year ORDER BY p_id, e_id DESC) AS GroupRank
FROM MyTable
)
UPDATE r_MyTable
SET flag = CASE WHEN GroupRank = 1 THEN 1 ELSE 0 END;
You can use max statement on e_id to get last value for the month, code is below:
IF OBJECT_ID('tempdb..#tmptest') IS NOT NULL
DROP TABLE #tmptest
SELECT
*
INTO
#tmptest
FROM
(
SELECT '1' p_id, '2011/11' mon_year, '20' e_id, '0' flag UNION ALL
SELECT '1', '2011/11', '21', '1' UNION ALL
SELECT '1', '2012/01', '22', '1' UNION ALL
SELECT '1', '2012/02', '23', '0' UNION ALL
SELECT '1', '2012/02', '24', '0' UNION ALL
SELECT '1', '2012/02', '25', '1' UNION ALL
SELECT '2', '2011/11', '28', '0' UNION ALL
SELECT '2', '2011/11', '29', '1' UNION ALL
SELECT '2', '2012/01', '30', '1'
) as tmp
SELECT
tmptest.*
FROM
(
SELECT
MAX(e_id) e_id
,p_id
,mon_year
FROM
#tmptest
GROUP BY
p_id,mon_year
) tblLastValueEID
INNER JOIN
#tmptest tmptest
ON
tmptest.p_id = tblLastValueEID.p_id
AND
tmptest.mon_year = tblLastValueEID.mon_year
AND
tmptest.e_id = tblLastValueEID.e_id