I have a table like this:
ID
C1
C2
C3
1
1
0
1
2
0
1
1
3
1
0
1
and I want to get to this:
ID
Category
Category_Value
1
C1
1
1
C2
0
1
C3
1
2
C1
0
2
C2
1
2
C3
0
3
C1
1
3
C2
0
3
C3
1
How can I do it? (I will add that I need It dynamic, because today I have 40 columns next week I can have 50 columns)
Thank you!
Another dynamic option is to Use UNPIVOT -
SELECT * FROM DATA
UNPIVOT (
Category_Value FOR Category IN (C1 AS 'C1', C2 AS 'C2', C3 AS 'C3')
);
Still you have to specify the column names as a list. If you want a fully dynamic query, You should try doing this at the presentation layer instead of database layer.
Demo.
One straightforward approach uses a union query:
SELECT ID, 'C1' AS Category, C1 AS Category_Value FROM yourTable
UNION ALL
SELECT ID, 'C2', C2 FROM yourTable
UNION ALL
SELECT ID, 'C3', C3 FROM yourTable
ORDER BY ID, Category;
Each row Total value go for the set OP value for the next row, except the first row
My Table Data
Id
WarehouseId
ProductId
OP
RE
IS
Total
1
100
10000
10
0
0
10
2
100
10000
0
0
5
5
4
100
10000
0
15
0
15
5
101
10001
15
0
0
15
6
101
10001
0
0
5
5
8
101
10001
0
15
0
15
9
101
10002
25
0
0
25
10
101
10002
0
0
10
10
11
101
10002
0
15
0
15
I want to show below result (OP+RE)-IS=Total
Id
WarehouseId
ProductId
OP
RE
IS
Total
1
100
10000
10
0
0
10
2
100
10000
10
0
5
5
4
100
10000
5
15
0
20
5
101
10001
15
0
0
15
6
101
10001
15
0
5
10
8
101
10001
10
15
0
25
9
101
10002
25
0
0
25
10
101
10002
25
0
10
15
11
101
10002
15
15
0
30
You can use recursive subquery factoring for that purpose like below. You need to rank your data as you have some gaps between IDs in your data. Column name = IS is not allowed, You should use "IS" enclosed by ".
with t1 ( ID, WAREHOUSEID, PRODUCTID, OP, RE, "IS", RNB, rnb_per_wh_prod) as (
select ID, WAREHOUSEID, PRODUCTID, OP, RE, "IS"
, row_number()over(order by WAREHOUSEID, PRODUCTID, ID) rnb
, row_number()over(partition by WAREHOUSEID, PRODUCTID order by ID) rnb_per_wh_prod
from Your_table t
), cte (ID, WAREHOUSEID, PRODUCTID, OP, RE, "IS", Total, RNB) as (
select ID, WAREHOUSEID, PRODUCTID, OP, RE, "IS", OP + RE - "IS", RNB
from t1
where rnb_per_wh_prod = 1
union all
select t1.ID
, t1.WAREHOUSEID
, t1.PRODUCTID
, case when t1.op = 0 then c.OP + c.RE - c."IS" else t1.OP end as OP
, t1.RE
, t1."IS"
, case when t1.op = 0 then c.OP + c.RE - c."IS" else t1.OP end + t1.RE - t1."IS" total
, t1.RNB
from cte c
join t1 on (t1.RNB = c.RNB + 1
and c.WAREHOUSEID = t1.WAREHOUSEID
and c.PRODUCTID = t1.PRODUCTID)
)
select ID, WAREHOUSEID, PRODUCTID, OP, RE, "IS", TOTAL
from cte
order by id
;
If I understand the problem correctly, "every 3 row" is a coincidence in your data; in fact, the computation must be done separately for each product in each warehouse, no matter how many rows there are for each distinct combination. And the "id" column is in reality some sort of timestamp - ordering is by "id".
If so, you can do it all in a single query using analytic sum(). Instead of creating a table for testing, I included all the sample data in a WITH clause at the top of the query itself; you can remove the WITH clause, and use your actual table and column names. I also changed the column name is to is_ since is is a reserved keyword, it can't be a column name.
Note also that I am ignoring your existing total column completely (I didn't even include it in the sample data); I assume it doesn't exist in your real-life data, and instead it is part of your attempt at a solution. You don't need it - not in the way you have it in your question.
with
sample_data (id, warehouseid, productid, op, re, is_) as (
select 1, 100, 10000, 10, 0, 0 from dual union all
select 2, 100, 10000, 0, 0, 5 from dual union all
select 4, 100, 10000, 0, 15, 0 from dual union all
select 5, 101, 10001, 15, 0, 0 from dual union all
select 6, 101, 10001, 0, 0, 5 from dual union all
select 8, 101, 10001, 0, 15, 0 from dual union all
select 9, 101, 10002, 25, 0, 0 from dual union all
select 10, 101, 10002, 0, 0, 10 from dual union all
select 11, 101, 10002, 0, 15, 0 from dual
)
select id, warehouseid, productid,
nvl(sum(op + re - is_) over (partition by warehouseid, productid
order by id rows between unbounded preceding and 1 preceding),
op) as op,
re, is_,
sum(op + re - is_) over
(partition by warehouseid, productid order by id) as total
from sample_data
;
ID WAREHOUSEID PRODUCTID OP RE IS_ TOTAL
------ ----------- ---------- ---------- ---------- ---------- ----------
1 100 10000 10 0 0 10
2 100 10000 10 0 5 5
4 100 10000 5 15 0 20
5 101 10001 15 0 0 15
6 101 10001 15 0 5 10
8 101 10001 10 15 0 25
9 101 10002 25 0 0 25
10 101 10002 25 0 10 15
11 101 10002 15 15 0 30
I have a temp table using to test and need direction with some analytics function. Still trying to figure out my real solution.. and any help to lead me in right direction will be appreciated.
A1 B1
40 5
50 4
60 3
70 2
90 1
Tyring to find the previous value and subtract and add the column
SELECT A1, B1,
(A1-B1) AS C1,
(A1-B1) + LEAD((A1-B1),1,0) OVER (ORDER BY ROWNUM) AS G1
FROM TEST;
The output is not what I expect
A1 B1 C1
40 5 35
50 4 46
60 3 57
70 2 68
90 1 89
From last rows (5th row), first subtract A1 -B2 to get C1..then (C1+ previous A1) - previous row B1 that is ---> 89 + 70 - 2 = 157 (save results in C1 previous row)
4th row: 157+60 -3 = 214
repeat until the first row...
Expected final output should be ;--
A1 B1 C1
40 5 295
50 4 260
60 3 214
70 2 157
90 1 89
LAG and LEAD only get a single row's value not an aggregation of multiple rows and it is not applied recursively.
You want:
SELECT A1,
B1,
SUM( A1 - B1 ) OVER ( ORDER BY ROWNUM
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
) AS C1
FROM test;
i have a table in hive with two columns: session_id and duration_time like this:
|| session_id || duration||
1 14
1 10
1 20
1 10
1 12
1 16
1 8
2 9
2 6
2 30
2 22
i want to add a new column with unique id when:
the session_id is changing or the duration_time > 15
i want the output to be like this:
session_id duration unique_id
1 14 1
1 10 1
1 20 2
1 10 2
1 12 2
1 16 3
1 8 3
2 9 4
2 6 4
2 30 5
2 22 6
any ideas how to do that in hive QL?
thanks!
SQL tables represent unordered sets. You need a column specifying the ordering of the values, because you seem to care about the ordering. This could be an id column or a created-at column, for instance.
You can do this using a cumulative sum:
select t.*,
sum(case when duration > 15 or seqnum = 1 then 1 else 0 end) over
(order by ??) as unique_id
from (select t.*,
row_number() over (partition by session_id order by ??) as seqnum
from t
) t;
Am having a case where I have transaction and this transaction consists of several steps. I want to return the first occurrence of this transaction, for example:
Trn Loc step
111 0 1
111 0 2
111 0 3
222 3 1
222 3 2
333 5 1
333 5 2
333 5 3
and i want to get this result :
tran loc
111 0
222 3
333 5
I think it is supposed to be done by partition function but I don't know how...any help please?
select t.trn, t.loc
from (select trn, loc, ROW_NUMBER() OVER (PARTITION BY trn, loc ORDER BY trn, loc) as rnum
from table ) t
where t.rnum = 1
Or you can use RANK() function instead of ROW_NUMBER(), rest of syntax is same.
http://www.techonthenet.com/oracle/functions/rank.php