I am going bonkers with this one simple SQL question - sql

Input table:
STAGE_NO
STAGE_ENTERED_DATE
0
2015-12-01 14:16:47
1
null
2
null
3
null
4
null
5
null
6
2017-02-12 0:00:00
7
2017-12-12 0:00:00
I want a new column that will give me the next stage_no where "stage_entered_date" is not-null.
This is the result that I am expecting:
STAGE_NO
STAGE_ENTERED_DATE
Next_Stage
0
2015-12-01 14:16:47
6
1
null
6
2
null
6
3
null
6
4
null
6
5
null
6
6
2017-02-12 0:00:00
7
7
2017-12-12 0:00:00
null
Disclaimer: Next_Stage column means next_stage where date is not null.

You can do this using the lead window function, ignoring nulls, and redefining nulls as the null in a different column using the IFF function:
with T1 as
(
select
COLUMN1::int as "STAGE_NO",
COLUMN2::timestamp as "STAGE_ENTERED_DATE"
from (values
('0','2015-12-01 14:16:47'),
('1',null),
('2',null),
('3',null),
('4',null),
('5',null),
('6','2017-02-12 0:00:00'),
('7','2017-12-12 0:00:00')
)
)
select STAGE_NO
,STAGE_ENTERED_DATE
,lead(iff(STAGE_ENTERED_DATE is not null, STAGE_NO, null))
ignore nulls over (partition by null order by STAGE_NO) as NEXT_STAGE
from T1
;
STAGE_NO
STAGE_ENTERED_DATE
NEXT_STAGE
0
2015-12-01 14:16:47.000000000
6
1
null
6
2
null
6
3
null
6
4
null
6
5
null
6
6
2017-02-12 00:00:00.000000000
7
7
2017-12-12 00:00:00.000000000
null
This will perform the stage calculation across the entire table. You probably have something like a customer, company, or some other "thing" that goes through these stages. You can specify what that is using a partition by clause in the window function. It's currently set to null, but you can simply change it to the column that defines the sets of rows for the phases.

Related

Transpose hirarchy table

I need some help with an table that consists of hirarchy data and I want to get a corresponding view out of it.
I have the following table with some sample data given:
AccountTypeCategoryTreeID
ParentViewTypeID
ParentAccountTypeCategoryID
ChildAccountTypeCategoryID
ChildAccountTypeGroupID
ChildAccountTypeID
SortOrder
2
NULL
7
23
NULL
NULL
10
3
91812
NULL
7
NULL
NULL
10
4
NULL
7
20
NULL
NULL
20
5
NULL
23
NULL
NULL
90584
20
6
91812
NULL
NULL
1
NULL
20
7
NULL
23
NULL
NULL
NULL
30
8
NULL
12
NULL
NULL
90586
10
9
NULL
23
12
NULL
NULL
40
10
91830
NULL
NULL
NULL
90584
10
11
91812
NULL
NULL
NULL
90581
30
The column ParentViewTypeID is always the root element of an tree. The columns ChildAccountTypeID and ChildAccountTypeGroupID are always the last element in the tree. The ParentAccountTypeCategoryID and ChildAccountTypeCategoryID represends the structure.
I have created the statement:
WITH hirachy
AS
(SELECT
catct.ParentViewTypeID AS [Parent]
,COALESCE(catct.ChildAccountTypeID, catct.ChildAccountTypeGroupID, catct.ChildAccountTypeCategoryID) AS [Child]
,catct.SortOrder
,1 AS [Level]
FROM CPM_AccountTypeCategoryTree catct
WHERE catct.ParentViewTypeID IS NOT NULL
UNION ALL
SELECT
Child.ParentAccountTypeCategoryID
,COALESCE(Child.ChildAccountTypeID, Child.ChildAccountTypeGroupID, Child.ChildAccountTypeCategoryID) AS [Child]
,child.SortOrder
,[Level] + 1 AS [Level]
FROM CPM_AccountTypeCategoryTree Child
JOIN hirachy g ON g.Child = Child.ParentAccountTypeCategoryID)
SELECT * FROM hirachy
ORDER BY [Level] ASC, SortOrder ASC
that gives me the following result set:
Parent
Child
SortOrder
Level
91830
90584
10
1
91812
7
10
1
91812
1
20
1
91812
90581
30
1
7
23
10
2
7
20
20
2
23
83414
10
3
23
90584
20
3
23
NULL
30
3
23
12
40
3
12
90586
10
4
So far so good.
But actualy I want something like this:
Root
Level1
Level2
Level3
Level4
91830
90584
91812
7
23
83414
91812
7
23
90584
91812
7
23
NULL
91812
7
23
12
90586
91812
7
20
91812
1
91812
90581
Can I use my current resultset to create my desired table or do I need a different solution? As the depth of the hirachy is not fixed, I know that I would need some dynamic sql statement. But for now I just need to know how to set up the basic statement.
Hope someone can help me to crack the nut...
Thanks in advance
Alex

Joining two tables where date in second table should be first date after date in first table i.e earliest date after date in first table

Problem statement description :-
I have two tables - table1 and table2 . table1 contains data of quantity buy of id=7 and table2 contain data of quantity sold of same id=7. Both table1 and table2 is sorted according to date i.e from oldest to latest date and every time only 1 quantity is buy or sold.
table1:
table1
date_buy
id
qty_buy
rolling_sum_qty_buy
30-07-2019
7
1
1
20-10-2019
7
1
2
17-01-2020
7
1
3
15-02-2020
7
1
4
15-02-2020
7
1
5
15-02-2020
7
1
6
14-07-2021
7
1
7
19-09-2021
7
1
8
25-12-2021
7
1
9
30-12-2021
7
1
10
10-02-2022
7
1
11
15-03-2022
7
1
12
15-03-2022
7
1
13
14-06-2022
7
1
14
table2:-
table2
date_sold
id
qty_sold
rolling_sum_qty_sold
01-08-2019
7
1
1
15-09-2019
7
1
2
27-12-2019
7
1
3
01-02-2020
7
1
4
12-02-2020
7
1
5
25-07-2021
7
1
6
25-07-2021
7
1
7
28-08-2021
7
1
8
10-09-2021
7
1
9
12-09-2021
7
1
10
25-04-2022
7
1
11
-- SQL scrtpt of table1:
CREATE TABLE IF NOT EXISTS table1 (
`date_buy` DATETIME,
`id` INT,
`qty_buy` INT,
`rolling_sum_qty_buy` INT
);
INSERT INTO table1 VALUES
('2019-07-30 00:00:00',7,1,1),
('2019-10-20 00:00:00',7,1,2),
('2020-01-17 00:00:00',7,1,3),
('2020-02-15 00:00:00',7,1,4),
('2020-02-15 00:00:00',7,1,5),
('2020-02-15 00:00:00',7,1,6),
('2021-07-14 00:00:00',7,1,7),
('2021-09-19 00:00:00',7,1,8),
('2021-12-25 00:00:00',7,1,9),
('2021-12-30 00:00:00',7,1,10),
('2022-02-10 00:00:00',7,1,11),
('2022-03-15 00:00:00',7,1,12),
('2022-03-15 00:00:00',7,1,13),
('2022-06-14 00:00:00',7,1,14);
-- sql script of table2:
CREATE TABLE IF NOT EXISTS table2 (
`date_sold` DATETIME,
`id` INT,
`qty_sold` INT,
`rolling_sum_qty_sold` INT
);
INSERT INTO table2 VALUES
('2019-08-01 00:00:00',7,1,1),
('2019-09-15 00:00:00',7,1,2),
('2019-12-27 00:00:00',7,1,3),
('2020-02-01 00:00:00',7,1,4),
('2020-02-12 00:00:00',7,1,5),
('2021-07-25 00:00:00',7,1,6),
('2021-07-25 00:00:00',7,1,7),
('2021-08-28 00:00:00',7,1,8),
('2021-09-10 00:00:00',7,1,9),
('2021-09-12 00:00:00',7,1,10),
('2022-04-25 00:00:00',7,1,11);
-- Now, i want to join this two table on two condition
for every date i.e date_buy column in table1 i should get output where date i.e date_sold is greater than date_buy and i want first date i.e. date_sold which is greater than that particular date i.e date_buy.
i also want those rows from table1 in my output which does not get joined with table2
so that i can easily find out the remaining quantity because in table1 i have quantity buy and after joining with table2 i will get quantity sold, so the cases where i get null values then in that case i can assume that that much quantity is remaining.
--My output:-
Earlier when there was no date issue then i was simply using left join to join table1 and table2 on rolling sum condition and where there was null cases i was taking sum of qty to get remaining qty but right now i have that condition too so i cant use rolling_sum_cond column directly in join condition.
-- query which i was using and output which i was getting earlier
select * from table1
left join table2
on table1.rolling_sum_qty_buy=table2.rolling_sum_qty_sold
date_buy
id
qty_buy
rolling_sum_qty_buy
date_sold
id-2
qty_sold
rolling_sum_qty_sold
30-07-2019
7
1
1
01-08-2019
7
1
1
20-10-2019
7
1
2
15-09-2019
7
1
2
17-01-2020
7
1
3
27-12-2019
7
1
3
15-02-2020
7
1
4
01-02-2020
7
1
4
15-02-2020
7
1
5
12-02-2020
7
1
5
15-02-2020
7
1
6
25-07-2021
7
1
6
14-07-2021
7
1
7
25-07-2021
7
1
7
19-09-2021
7
1
8
28-08-2021
7
1
8
25-12-2021
7
1
9
10-09-2021
7
1
9
30-12-2021
7
1
10
12-09-2021
7
1
10
10-02-2022
7
1
11
25-04-2022
7
1
11
15-03-2022
7
1
12
NULL
NULL
NULL
NULL
15-03-2022
7
1
13
NULL
NULL
NULL
NULL
14-06-2022
7
1
14
NULL
NULL
NULL
NULL
and to find out remaining quantity , i was using null condition
query:-
with cte as
(
select * from table1
left join table2
on table1.rolling_sum_qty_buy=table2.rolling_sum_qty_sold
)
select sum(qty_buy) as remaining_qty
from cte
where cte.date_sold is null
remaining_qty
3
-- my expectation
now i have to use date condition also to get the output
-- Expected Output
date_buy
id
qty_buy
rolling_sum_qty_buy
date_sold
id
qty_sold
rolling_sum_qty_sold
30-07-2019
7
1
1
01-08-2019
7
1
1
20-10-2019
7
1
2
27-12-2019
7
1
3
17-01-2020
7
1
3
01-02-2020
7
1
4
15-02-2020
7
1
4
25-07-2021
7
1
6
15-02-2020
7
1
5
25-07-2021
7
1
7
15-02-2020
7
1
6
28-08-2021
7
1
8
14-07-2021
7
1
7
10-09-2021
7
1
9
19-09-2021
7
1
8
25-04-2022
7
1
11
25-12-2021
7
1
9
NULL
NULL
NULL
NULL
30-12-2021
7
1
10
NULL
NULL
NULL
NULL
10-02-2022
7
1
11
NULL
NULL
NULL
NULL
15-03-2022
7
1
12
NULL
NULL
NULL
NULL
15-03-2022
7
1
13
NULL
NULL
NULL
NULL
14-06-2022
7
1
14
NULL
NULL
NULL
NULL
-- Please help me to get the following output. Any help would be appreciated.
I am using postgresql.
That was a challenging one.
with recursive cte as
(
select t2.date_sold
,t2.rolling_sum_qty_sold
,true as is_match
,1 as last_rolling_sum_qty_buy
from t2 join t on t2.rolling_sum_qty_sold = t.rolling_sum_qty_buy
where t2.rolling_sum_qty_sold = 1
union all
select t2.date_sold
,t2.rolling_sum_qty_sold
,t2.date_sold >= t.date_buy
,cte.last_rolling_sum_qty_buy + case when t2.date_sold >= t.date_buy then 1 else 0 end
from t2
join cte on cte.rolling_sum_qty_sold + 1 = t2.rolling_sum_qty_sold
join t on t.rolling_sum_qty_buy = cte.last_rolling_sum_qty_buy + 1
)
select t.date_buy
,t.id
,t.qty_buy
,t.rolling_sum_qty_buy
,cte.date_sold
,cte.rolling_sum_qty_sold
from t left join cte on cte.last_rolling_sum_qty_buy = t.rolling_sum_qty_buy and is_match
date_buy
id
qty_buy
rolling_sum_qty_buy
date_sold
rolling_sum_qty_sold
2019-07-30
7
1
1
2019-08-01
1
2019-10-20
7
1
2
2019-12-27
3
2020-01-17
7
1
3
2020-02-01
4
2020-02-15
7
1
4
2021-07-25
6
2020-02-15
7
1
5
2021-07-25
7
2020-02-15
7
1
6
2021-08-28
8
2021-07-14
7
1
7
2021-09-10
9
2021-09-19
7
1
8
2022-04-25
11
2021-12-25
7
1
9
null
null
2021-12-30
7
1
10
null
null
2022-02-10
7
1
11
null
null
2022-03-15
7
1
12
null
null
2022-03-15
7
1
13
null
null
2022-06-14
7
1
14
null
null
Fiddle

Insert multiple rows from result of Average by date and id

I have a table with 1 result per day like this :
id | item_id | date | amount
-------------------------------------
1 1 2019-01-01 1
2 1 2019-01-02 2
3 1 2019-01-03 3
4 1 2019-01-04 4
5 1 2019-01-05 5
6 2 2019-01-01 1
7 2 2019-01-01 2
8 2 2019-01-01 3
9 2 2019-01-01 4
10 2 2019-01-01 5
11 3 2019-01-01 1
12 3 2019-01-01 2
13 3 2019-01-01 3
14 3 2019-01-01 4
15 3 2019-01-01 5
First I was trying to average the column amount for each day.
SELECT
x.item_id AS id,avg(x.amount) AS result
FROM
(SELECT
il.item_id, il.amount,
ROW_NUMBER() OVER (PARTITION BY il.item_id ORDER BY il.date DESC) rn
FROM
item_prices il) x
WHERE
x.rn BETWEEN 1 AND 50
GROUP BY
x.item_id
The result is going to be the following if calculated on 2019-01-05
item_id | average
1 3
2 3
3 3
or, if calculated 2019-01-04
item_id | average
1 2.5
2 2.5
3 2.5
My goal is to run the Average query , every day that would update the average automatically and insert it in 5th column "average" :
id | item_id | date | amount | average
5 1 2019-01-05 5 3
10 2 2019-01-05 5 3
15 3 2019-01-05 5 3
Issue is that every example i can find with Insert the Select they only update one row and they are over another table there is also the most recent date issue...
Can someone point me in the right direction?
Perhaps you want to see running average every day. Storing the value as a separate column is bound to cause problems especially when the rows are updated/deleted, the column also needs to be updated and hence will require complex triggers.
Simply create a View and run whenever you want to check the average directly from that View.
CREATE OR REPLACE VIEW v_item_prices AS
SELECT t.*,avg(t.amount) OVER ( PARTITION BY item_id order by date)
AS average FROM item_prices t
order by item_id,date
DEMO

Getting date difference between consecutive rows in the same group

I have a database with the following data:
Group ID Time
1 1 16:00:00
1 2 16:02:00
1 3 16:03:00
2 4 16:09:00
2 5 16:10:00
2 6 16:14:00
I am trying to find the difference in times between the consecutive rows within each group. Using LAG() and DATEDIFF() (ie. https://stackoverflow.com/a/43055820), right now I have the following result set:
Group ID Difference
1 1 NULL
1 2 00:02:00
1 3 00:01:00
2 4 00:06:00
2 5 00:01:00
2 6 00:04:00
However I need the difference to reset when a new group is reached, as in below. Can anyone advise?
Group ID Difference
1 1 NULL
1 2 00:02:00
1 3 00:01:00
2 4 NULL
2 5 00:01:00
2 6 00:04:00
The code would look something like:
select t.*,
datediff(second, lag(time) over (partition by group order by id), time)
from t;
This returns the difference as a number of seconds, but you seem to know how to convert that to a time representation. You also seem to know that group is not acceptable as a column name, because it is a SQL keyword.
Based on the question, you have put group in the order by clause of the lag(), not the partition by.

SQL: Create a new id column that changes based on the values of other three columns? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have a table with three columns named cid, orderdate, and priororderdate among others.
Here is how the table looks:
cid orderdate priororderdate position
12 NULL NULL 1
12 NULL NULL 2
12 NULL NULL 3
12 2014-08-08 23:25 NULL 1
12 2014-08-08 23:25 NULL 2
12 2014-08-08 23:25 NULL 3
12 2014-08-08 23:25 NULL 4
12 2014-09-06 17:19 2014-08-08 23:25 1
12 2014-09-06 17:19 2014-08-08 23:25 2
12 2014-09-06 17:19 2014-08-08 23:25 3
13 NULL NULL 1
13 NULL NULL 2
13 NULL NULL 3
The combination of the columns cid, orderdatetime, and priororderdatetime defines a unique fpid (a new column I want to create). Hence, the final result would be:
cid orderdate priororderdate position fpid
12 NULL NULL 1 1
12 NULL NULL 2 1
12 NULL NULL 3 1
12 2014-08-08 23:25 NULL 1 2
12 2014-08-08 23:25 NULL 2 2
12 2014-08-08 23:25 NULL 3 2
12 2014-08-08 23:25 NULL 4 2
12 2014-09-06 17:19 2014-08-08 23:25 1 3
12 2014-09-06 17:19 2014-08-08 23:25 2 3
12 2014-09-06 17:19 2014-08-08 23:25 3 3
13 NULL NULL 1 4
13 NULL NULL 2 4
13 NULL NULL 3 4
How can I create the fpid column?
You can do this using dense_rank() in a select query:
select t.*,
dense_rank() over (order by cid, orderdate, priororderdate) as fpid
from table t;
If you have the column fpid already in the table and want to update it:
with toupdate as (
select t.*,
dense_rank() over (order by cid, orderdate, priororderdate) as new_fpid
from table t
)
update toupdate
set fpid = new_fpid;
(If you want to add it, you can use an alter table statement.)
It's a little bit confusion that you say that fpid is unique, but looking at your desired output, it looks like you want to use ROW_NUMBER().
UPDATE tab2 t SET fpid =
(SELECT ROW_NUMBER () OVER (ORDER BY cid)
FROM tab2
GROUP BY cid, orderdate, priororderdate
WHERE t.cid = cid
AND t.orderdate = orderdate
AND t.priororderdate = priororderdate)