Nested grouping in internal table - abap

I would like to get all lines, which have different entries to fields anln1 and anln2.
For this I need a fitting OpenSQL statement.
E.g. there is the following table:
anln1 | anln2 | datum | psp | przt
------------------------------------------
10007 | 0 | 20140101 | 12345678 | 1
10007 | 0 | 20140101 | 11111111 | 99
10007 | 1 | 20140101 | 12345678 | 1
10007 | 1 | 20140101 | 11111111 | 99
All entries for anln1 + anln2 should repeat their combination of datum, psp and przt if there is another subnumber, e.g. anln2=1.
Unfortunately my table has breaches to this specification (SQLFiddle: http://sqlfiddle.com/#!2/f5d1f):
anln1 | anln2 | datum | psp | przt
------------------------------------------
10000 | 0 | 20140101 | 12345678 | 60
10000 | 0 | 20140101 | 11111111 | 40
10000 | 1 | 20140101 | 11111111 | 100
10000 | 2 | 20140101 | 11111111 | 100
10000 | 3 | 20140101 | 22222222 | 100
10001 | 0 | 20140101 | 12312312 | 100
10001 | 1 | 20140101 | 12312312 | 100
10001 | 2 | 20140101 | 12312312 | 100
10002 | 0 | 20140101 | 11111111 | 100
10003 | 0 | 20140101 | 11111111 | 100
10004 | 0 | 20140101 | 11111111 | 100
10005 | 0 | 20140101 | 22222222 | 100
10005 | 1 | 20140101 | 33333333 | 100
10006 | 0 | 20140101 | 11111111 | 20
10006 | 0 | 20140101 | 22222222 | 80
10006 | 1 | 20140101 | 11111111 | 30
10006 | 1 | 20140101 | 11111111 | 70
10007 | 0 | 20140101 | 12345678 | 1
10007 | 0 | 20140101 | 11111111 | 99
10007 | 1 | 20140101 | 12345678 | 1
10007 | 1 | 20140101 | 11111111 | 99
As a result to my query I need all the lines identified, where my specification is breached. The correct lines should be just left out.
Correct lines are the ones where anln1 is 10001, 10002, 10003, 10004, 10007.
So, the result should look like this:
anln1 | anln2 | datum | psp | przt
------------------------------------------
10000 | 0 | 20140101 | 12345678 | 60
10000 | 0 | 20140101 | 11111111 | 40
10000 | 1 | 20140101 | 11111111 | 100
10000 | 2 | 20140101 | 11111111 | 100
10000 | 3 | 20140101 | 22222222 | 100
10005 | 0 | 20140101 | 22222222 | 100
10005 | 1 | 20140101 | 33333333 | 100
10006 | 0 | 20140101 | 11111111 | 20
10006 | 0 | 20140101 | 22222222 | 80
10006 | 1 | 20140101 | 11111111 | 30
10006 | 1 | 20140101 | 11111111 | 70
I tried things with GROUP BY, HAVING and COUNT(...) > 1, but I didn't get to a useful result. Is this even solvable with (Open)SQL?
Really looking forward to your help! Please use my SQLFiddle (http://sqlfiddle.com/#!2/f5d1f) to try around.

After selecting the entries with anln2 <> 0, I worked on with an internal table.
First I sorted the selected result like this:
SORT gt_internaltable BY anln1 anln2 datum psp przt.
Then I looped over the internal table and removed all the double entries...
LOOP AT gt_internaltable INTO gs_tablerow.
AT NEW anln1.
CLEAR g_count.
ENDAT.
g_count = g_count + 1.
AT END OF anln1.
IF g_count > 1. " delete double entries
DELETE gt_internaltable WHERE anln1 = gs_tablerow-anln1
AND anln2 = gs_tablerow-anln2
AND datum = gs_tablerow-datum
AND psp = gs_tablerow-psp
AND przt = gs_tablerow-przt.
ENDIF.
ENDAT.
ENDLOOP.
In the end, a the list of the entries breaching my specification is left over in gt_internaltable.

I do not thinks it is achievable through OpenSQL.
Here is how to achieve this using modern ABAP syntax using grouping:
TYPES: BEGIN OF ty_anla,
anln1 TYPE anln1,
anln2 TYPE anln2,
datum TYPE erdat,
psp TYPE c LENGTH 8,
przt TYPE i,
END OF ty_anla,
tty_anla TYPE STANDARD TABLE OF ty_anla WITH NON-UNIQUE KEY primary_key COMPONENTS anln1.
DATA: lt_input TYPE tty_anla,
lt_output TYPE tty_anla.
lt_output = lt_input =
VALUE #( ( anln1 = 10000 anln2 = 0 datum = '20140101' psp = 12345678 przt = 60 )
( anln1 = 10000 anln2 = 0 datum = '20140101' psp = 11111111 przt = 40 )
( anln1 = 10000 anln2 = 1 datum = '20140101' psp = 11111111 przt = 100 )
( anln1 = 10000 anln2 = 2 datum = '20140101' psp = 11111111 przt = 100 )
( anln1 = 10000 anln2 = 3 datum = '20140101' psp = 22222222 przt = 100 )
( anln1 = 10001 anln2 = 0 datum = '20140101' psp = 12312312 przt = 100 )
( anln1 = 10001 anln2 = 1 datum = '20140101' psp = 12312312 przt = 100 )
( anln1 = 10001 anln2 = 2 datum = '20140101' psp = 12312312 przt = 100 )
( anln1 = 10002 anln2 = 0 datum = '20140101' psp = 11111111 przt = 100 )
( anln1 = 10003 anln2 = 0 datum = '20140101' psp = 11111111 przt = 100 )
( anln1 = 10004 anln2 = 0 datum = '20140101' psp = 11111111 przt = 100 )
( anln1 = 10005 anln2 = 0 datum = '20140101' psp = 22222222 przt = 100 )
( anln1 = 10005 anln2 = 1 datum = '20140101' psp = 33333333 przt = 100 )
( anln1 = 10006 anln2 = 0 datum = '20140101' psp = 11111111 przt = 20 )
( anln1 = 10006 anln2 = 0 datum = '20140101' psp = 22222222 przt = 80 )
( anln1 = 10006 anln2 = 1 datum = '20140101' psp = 11111111 przt = 30 )
( anln1 = 10006 anln2 = 1 datum = '20140101' psp = 11111111 przt = 70 )
( anln1 = 10007 anln2 = 0 datum = '20140101' psp = 12345678 przt = 1 )
( anln1 = 10007 anln2 = 0 datum = '20140101' psp = 11111111 przt = 99 )
( anln1 = 10007 anln2 = 1 datum = '20140101' psp = 12345678 przt = 1 )
( anln1 = 10007 anln2 = 1 datum = '20140101' psp = 11111111 przt = 99 )
).
LOOP AT lt_input ASSIGNING FIELD-SYMBOL(<fs_inp>) USING KEY primary_key GROUP BY ( anln1 = <fs_inp>-anln1 index = GROUP INDEX size = GROUP SIZE ) REFERENCE INTO DATA(common_anln1).
LOOP AT GROUP common_anln1 ASSIGNING FIELD-SYMBOL(<fs_member>) GROUP BY ( datum = <fs_member>-datum psp = <fs_member>-psp przt = <fs_member>-przt index = GROUP INDEX size = GROUP SIZE ) REFERENCE INTO DATA(common_key).
DATA(common_key_size) = common_key->*-size.
EXIT.
ENDLOOP.
CHECK common_anln1->*-size = common_key_size.
DELETE lt_output WHERE anln1 = common_anln1->*-anln1.
ENDLOOP.
Here we group first by ANLN1 key and within these groups we then check datum+psr+psp key so that the group sizes are equal. This means all ANLN1s possess the same key.
In the outcome in the lt_output you will see the desired result:
10000 0 2014-01-01 12345678 60
10000 0 2014-01-01 11111111 40
10000 1 2014-01-01 11111111 100
10000 2 2014-01-01 11111111 100
10000 3 2014-01-01 22222222 100
10005 0 2014-01-01 22222222 100
10005 1 2014-01-01 33333333 100
10006 0 2014-01-01 11111111 20
10006 0 2014-01-01 22222222 80
10006 1 2014-01-01 11111111 30
10006 1 2014-01-01 11111111 70
10007 0 2014-01-01 12345678 1
10007 0 2014-01-01 11111111 99
10007 1 2014-01-01 12345678 1
10007 1 2014-01-01 11111111 99
10007 is here because it is not a correct line as per your definition All entries for anln1 + anln2 should repeat their combination of datum, psp and przt. Different 10007 anln2 values have different psp values.

Related

SQL Server - Manipulating Values to Create a String

I am trying to populate the column String_to_Use the way it displays on the 5th column from left to right, with values from the ID column, displaying the ranges with "-". Code below produces the last column string_to_use incorrectly.
select
t.*,
(case
when Checking_id = -2
then min(id) over (partition by grp) + '-' + max(id) over (partition by grp)
else id
end) as string_to_use
from
(select
t.*,
sum(case when Checking_id = -2 then 1 else 0 end) over (partition by id) as grp
from
t) t
order by
id;
Output:
ID Number ID IndexColumn String_To_Use Checking_id grp string_to_use
------------------------------------------------------------------------------
0000 1 0000 1 0000-1130 -2 1 0000-1210
1000 2 1000 2 0000-1130 -2 1 0000-1210
1020 3 1020 3 0000-1130 -2 1 0000-1210
1130 4 1130 4 0000-1130 -2 1 0000-1210
1198 5 NULL 9999 NULL NULL 0 NULL
1199 6 1199 5 1199-1210 -2 1 0000-1210
1210 7 1210 6 1199-1210 -2 1 0000-1210
1240 8 NULL 9999 NULL NULL 0 NULL
1250 9 NULL 9999 NULL NULL 0 NULL
1260 10 1260 7 1260 7 0 1260
1261 11 NULL 9999 NULL NULL 0 NULL
1280 12 NULL 9999 NULL NULL 0 NULL
1296 13 NULL 9999 NULL NULL 0 NULL
1298 14 NULL 9999 NULL NULL 0 NULL
1299 15 1299 8 1299 8 0 1299
1501 16 NULL 9999 NULL NULL 0 NULL
Can someone please help me with this? Thank you!
Have a look at the following query.
What i do is to create groups on the basis of difference between Number and IndexColumn.
ie my paritition by block is based upon groups up and until it meets up with a 9999 indexcol record.
After that i am getting the max id and the min id value of that group and concatenating using '-'
Here is a db-fiddle link
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=7bd4d3a489600b58740e2f82a478726b
In the end the query looks like this
create table t(ID varchar(10),Number1 int,ID2 varchar(10),indexcol int,String_To_Use varchar(100))
insert into t
select *
from (values
('0000',1 ,'0000',1 ,'0000-1130')
,('1000',2 ,'1000',2 ,'0000-1130')
,('1020',3 ,'1020',3 ,'0000-1130')
,('1130',4 ,'1130',4 ,'0000-1130')
,('1198',5 ,NULL ,9999,NULL )
,('1199',6 ,'1199',5 ,'1199-1210')
,('1210',7 ,'1210',6 ,'1199-1210')
,('1240',8 ,NULL ,9999,NULL )
,('1250',9 ,NULL ,9999,NULL )
,('1260',10,'1260',7 ,'1260' )
,('1261',11,NULL ,9999,NULL )
,('1280',12,NULL ,9999,NULL )
,('1296',13,NULL ,9999,NULL )
,('1298',14,NULL ,9999,NULL )
,('1299',15,'1299',8 ,'1299' )
,('1501',16,NULL ,9999,NULL )
)t(id,number1,id2,indexcol,string_to_use)
select *
,max(case when indexcol <> 9999 then id end) over(partition by Number1-indexcol)as max_val
,case when max(case when indexcol <> 9999 then id end) over(partition by Number1-indexcol)
= min(case when indexcol <> 9999 then id end) over(partition by Number1-indexcol)
then max(case when indexcol <> 9999 then id end) over(partition by Number1-indexcol)
else min(case when indexcol <> 9999 then id end) over(partition by Number1-indexcol)
+'-'+
max(case when indexcol <> 9999 then id end) over(partition by Number1-indexcol)
end as computed_string_to_use
from t
order by Number1
+------+---------+------+----------+---------------+---------+------------------------+
| ID | Number1 | ID2 | indexcol | String_To_Use | max_val | computed_string_to_use |
+------+---------+------+----------+---------------+---------+------------------------+
| 0000 | 1 | 0000 | 1 | 0000-1130 | 1130 | 0000-1130 |
| 1000 | 2 | 1000 | 2 | 0000-1130 | 1130 | 0000-1130 |
| 1020 | 3 | 1020 | 3 | 0000-1130 | 1130 | 0000-1130 |
| 1130 | 4 | 1130 | 4 | 0000-1130 | 1130 | 0000-1130 |
| 1198 | 5 | | 9999 | | | |
| 1199 | 6 | 1199 | 5 | 1199-1210 | 1210 | 1199-1210 |
| 1210 | 7 | 1210 | 6 | 1199-1210 | 1210 | 1199-1210 |
| 1240 | 8 | | 9999 | | | |
| 1250 | 9 | | 9999 | | | |
| 1260 | 10 | 1260 | 7 | 1260 | 1260 | 1260 |
| 1261 | 11 | | 9999 | | | |
| 1280 | 12 | | 9999 | | | |
| 1296 | 13 | | 9999 | | | |
| 1298 | 14 | | 9999 | | | |
| 1299 | 15 | 1299 | 8 | 1299 | 1299 | 1299 |
| 1501 | 16 | | 9999 | | | |
+------+---------+------+----------+---------------+---------+------------------------+

SQL delta calculation with varying records

I am calculating the difference of amounts between batch runs of calc_table and store it in delta_table. The number of records in calc_table per batch run can vary.
I can calculate the difference, but I am not sure how to handle new or deleted records since the JOINS in SQL would be different. I believe I need to use a FULL JOIN but I am having a problem constructing the SQL query.
Note: batch_id is not always incremented by 1. And the query should be in the calc_table since that is where the amount is stored. The delta_table will contain the differences between amounts of calc_table.
This is my current SQL: (I am using PostgreSQL)
select c2.batch_id, c2.c_id, c2.date,
(c2.amount1 - c1.amount1) as amount1, (c2.amount2 - c1.amount2) as amount2
from calc_table c1 inner join calc_table c2 on c1.c_id = c2.c_id
where c1.batch_id = 100 and c2.batch_id = 101
* c1.batch_id and c2.batch_id are PARAMETERS.
And this is giving me all the expected c_id (with deleted and new records). But i cannot construct it properly to give me my expected results for the delta calculation.
SELECT coalesce(c2.c_id, c1.c_id) as c_id
FROM
(select * from calc_table where batch_id = 100) c1
FULL OUTER JOIN
(select * from calc_table where batch_id = 101) c2
ON c1.id = c2.id
group by coalesce(c2.c_id, c1.c_id);
This is the first run of the calc_table: (batch_id = 100)
calc_table:
-----------------------------------------------------
id | batch_id | c_id | date | amount1 | amount2
-----------------------------------------------------
1 | 100 | C001 | 2017-03-01 | 100 | 200
2 | 100 | C002 | 2017-03-01 | 100 | 200
3 | 100 | C003 | 2017-03-01 | 100 | 200
If the user runs again: (batch_id = 101)
4 | 101 | C001 | 2017-03-01 | 200 | 200
5 | 101 | C002 | 2017-03-01 | 150 | 220
6 | 101 | C003 | 2017-03-01 | 170 | 250
7 | 101 | C004*| 2017-03-01 | 210 | 250
* C004 is a new record
Delta between them (batch_id 101 minus 100) should be calculated and stored in delta_table:
delta_table:
------------------------------------------------------
id | batch_id | c_id | date | amount1 | amount2
------------------------------------------------------
1 | 101 | C001 | 2017-03-01 | 100 | 0
2 | 101 | C002 | 2017-03-01 | 50 | 20
3 | 101 | C003 | 2017-03-01 | 70 | 50
4 | 101 | C004 | 2017-03-01 | 210 | 250
If the user runs again: (batch_id = 104, id 8-10)
* Rows 1-7 (same as before)
calc_table:
-----------------------------------------------------
id | batch_id | c_id | date | amount1 | amount2
-----------------------------------------------------
1 | 100 | C001 | 2017-03-01 | 100 | 200
2 | 100 | C002 | 2017-03-01 | 100 | 200
3 | 100 | C003 | 2017-03-01 | 100 | 200
4 | 101 | C001 | 2017-03-01 | 200 | 200
5 | 101 | C002 | 2017-03-01 | 150 | 220
6 | 101 | C003 | 2017-03-01 | 170 | 250
7 | 101 | C004 | 2017-03-01 | 210 | 250
8 | 104 | C001 | 2017-03-01 | 200 | 200
9 | 104 | C002 | 2017-03-01 | 400 | 200
10 | 104 | C003 | 2017-03-01 | 400 | 220
* Note: C004 was deleted
Delta between them (batch_id 104 minus 101) should be calculated and stored in delta_table:
* Rows 1-4 (same as before), new delta = id 5-8
delta_table:
------------------------------------------------------
id | batch_id | c_id | date | amount1 | amount2
------------------------------------------------------
1 | 101 | C001 | 2017-03-01 | 100 | 0
2 | 101 | C002 | 2017-03-01 | 50 | 20
3 | 101 | C003 | 2017-03-01 | 70 | 50
4 | 101 | C004 | 2017-03-01 | 210 | 250
5 | 104 | C001 | 2017-03-01 | 0 | 0
6 | 104 | C002 | 2017-03-01 | 250 | -20
7 | 104 | C003 | 2017-03-01 | 230 | -30
8 | 104 | C004 | 2017-03-01 | -210 | -250
Maybe try FULL JOIN?
Assuming that batch_id that you calculate delta for are always increments of 1. Something like this:
SELECT COALESCE(new.batch_id, old_padded_with_deleted.batch_id) AS batch_id,
COALESCE(new.c_id, old_padded_with_deleted.c_id) AS c_id,
COALESCE(new.date, old_padded_with_deleted.date) AS date, --new.amount1, old_padded_with_deleted.amount1,
CASE WHEN new.amount1 IS NULL THEN -old_padded_with_deleted.amount1 ELSE (new.amount1 - coalesce(old_padded_with_deleted.amount1, 0)) END AS amount1,
CASE WHEN new.amount2 IS NULL THEN -old_padded_with_deleted.amount2 ELSE (new.amount2 - coalesce(old_padded_with_deleted.amount2, 0)) END AS amount2
FROM calc_table new
FULL JOIN (
SELECT coalesce(old.batch_id, deleted.batch_id)+1 AS batch_id, coalesce(old.c_id, deleted.c_id) AS c_id, coalesce(old.date, deleted.date) AS date,
coalesce(old.amount1, deleted.amount1) AS amount1, coalesce(old.amount2, deleted.amount2) AS amount2
FROM delta_table AS deleted
FULL JOIN calc_table AS old ON old.batch_id = deleted.batch_id AND old.c_id = deleted.c_id
) AS old_padded_with_deleted ON old_padded_with_deleted.c_id = new.c_id
AND old_padded_with_deleted.batch_id = new.batch_id
WHERE
new.batch_id = 101 OR old_padded_with_deleted.batch_id = 101
Solved it using this SQL:
select c1.c_id,
sum(case when c1.batch_id = 100 then (c1.amount1 * -1) else (c1.amount1 * 1) end) as amount1
from calc_table c1
where c1.batch_id = 100 or c1.batch_id = 101
group by c1.c_id

SQL server SUM of MAX in different columns for each item

+---------+--------+-----+---------+-------+-----------+-------+-----------+--------+
| Quot_ID | Art_ID | Qty | Qty_Alt | Price | Price_Alt | Value | Value_Alt | Status |
+---------+--------+-----+---------+-------+-----------+-------+-----------+--------+
| 1000000 | 100000 | 10 | 0 | 100 | 0 | 1000 | 0 | lost |
| 1000000 | 100000 | 0 | 20 | 0 | 90 | 0 | 1800 | lost |
| 1000000 | 100000 | 0 | 30 | 0 | 80 | 0 | 2400 | won |
| 1000000 | 100000 | 0 | 40 | 0 | 70 | 0 | 2800 | lost |
| 1000000 | 200000 | 10 | 0 | 150 | 0 | 1500 | 0 | lost |
| 1000000 | 200000 | 0 | 20 | 0 | 140 | 0 | 2800 | lost |
| 1000000 | 200000 | 0 | 30 | 0 | 130 | 0 | 3900 | lost |
| 1000000 | 200000 | 0 | 40 | 0 | 120 | 0 | 4800 | lost |
+---------+--------+-----+---------+-------+-----------+-------+-----------+--------+
Above an example of a quotation.
I need the percentage 'won' / 'quoted'
'quoted' is defined as the Value (EUR) or ValueAlt (EUR) for each Article_ID where the Qty or Qty_Alt has the maximum value.
In this example both articles 100000 and 200000 are quoted with max value of 40 pieces. The corresponding Values are 2800 + 4800 = 7600 EUR.
The percentage won I am looking for is therefore 100 * 2400 / 7600 = 31.6%
This code
"SELECT a.Quot_ID, (a.Value + a.Value_Alt) FROM Quotations a LEFT JOIN Quotations b ON a.Quot_ID = b.Quot_ID AND (a.Qty + a.Qty_Alt) < (b.Qty + b.Qty_Alt) WHERE (b.Qty + b.Qty_Alt) is NULL ORDER BY a.QuotationCode"
gives me
1000000 2800
1000000 4800
Does any one know how I can change this into one result:
1000000 7600
OK, Almost there:
Thanks to Muhammad I now have
SELECT a.Quot_ID, sum(a.Value + a.Value_Alt) FROM Quotations a LEFT JOIN Quotations b ON a.Quot_ID = b.Quot_ID AND (a.Qty + a.Qty_Alt) < (b.Qty + b.Qty_Alt) WHERE (b.Qty + b.Qty_Alt) is NULL GROUP BY a.Quot_ID ORDER BY a.Quot_ID
Last step is to get the percentage 'won'
In this example 100 * 2400 / 7600 = 31,6%
Any ideas or hints?
Thanks in advance
SELECT a.Quot_ID, sum(a.Value + a.Value_Alt) , (a.Value_alt/(sum (a.value+a.value_alt))*100 as percentage FROM Quotations a LEFT JOIN Quotations b ON a.Quot_ID = b.Quot_ID AND (a.Qty + a.Qty_Alt) < (b.Qty + b.Qty_Alt) WHERE (b.Qty + b.Qty_Alt) is NULL GROUP BY a.Quot_ID ORDER BY a.QuotationCode

Select data with calculation in same data table

My Table is
itemcode in out sum value datetime PP
-------|---|---|-----------|-----------|---------
A1234 | 1 | 0 | 100 |04/03/2009 | E01
A1234 | 0 | 1 | -100 |05/03/2009 | E01
A1234 | 1 | 0 | 100 |06/03/2009 | E01
A1234 | 0 | 1 | -100 |07/03/2009 | E01
A1234 | 1 | 0 | 100 |08/03/2009 | E01
A1234 | 9 | 0 | 900 |09/03/2009 | S01
A1234 | 0 | 3 | -300 |10/03/2009 | S01
A1234 | 8 | 0 | 800 |11/03/2009 | S01
A1235 | 9 | 0 | 900 |12/03/2009 | E01
A1235 | 0 | 2 | -200 |13/03/2009 | E01
A1235 | 0 | 3 | -300 |14/03/2009 | E01
A1235 | 8 | 0 | 800 |15/03/2009 | S01
Result would be:
itemcode Remain sum value datetime PP
---------|--------|-----------|-----------|----
A1234 | 1 | 100 |08/03/2009 | E01
A1234 | 6 | 600 |09/03/2009 | S01
A1234 | 8 | 800 |11/03/2009 | S01
A1235 | 4 | 400 |12/03/2009 | E01
A1235 | 8 | 800 |15/03/2009 | S01
How to select such data and calculate how many stock remaining, group by same itemcode and pp,
list out in different in stock date
The way I would do this is use the SUM() function to sum the in column, as well as the out column, and subtract them to get the value that is in stock. Once you've done that, you can use the GROUP BY clause to group the columns you want. Intuitively, it works pretty closely to what you described.
You'll also have to do something with the datecolumn, and it seems that you want to produce the latest date in each group, so I've also selected the max date for that reason.
You didn't list the column names in your question, so I'm going on a limb here:
SELECT itemcode, (SUM(inColumn) - SUM(outColumn)) AS inStock, SUM(value) AS value, MAX(dateColumn) AS latestDate, pp
FROM myTable
GROUP BY itemcode, pp;
Here is the SQL Fiddle.

Query to find the first date after a specific grouped sum value

I have an article table that holds the current stock for each article. I need to know the last date when new stock has arrived, after running out of stock for that specific article.
The table looks like this.
+-----------+-----------------+-------+
| ArticleID | StockDate | Stock |
+-----------+-----------------+-------+
| 1 | 1/1/2012 10:15 | 100 |
| 1 | 2/1/2012 13:39 | -50 |
| 1 | 2/1/2012 15:17 | -50 |
| 1 | 4/1/2012 08:05 | 100 |
| 2 | 5/1/2012 09:48 | 50 |
| 1 | 6/1/2012 14:21 | -25 |
| 1 | 7/1/2012 16:01 | 10 |
| 2 | 8/1/2012 13:42 | -10 |
| 1 | 9/1/2012 09:56 | -85 |
| 1 | 13/1/2012 08:12 | 100 |
| 1 | 13/1/2012 10:50 | -15 |
+-----------+-----------------+-------+
The output should look like this.
+-----------+-----------------+
| ArticleID | StockDate |
+-----------+-----------------+
| 2 | 5/1/2012 09:48 |
| 1 | 13/1/2012 08:12 |
+-----------+-----------------+
How did i get this output? ArticleID 1 had a 100 in stock but reached 0 for the first time on 2/1/2012 15:17. Then new stock arrived and it hit 0 again at 9/1/2012 09:56. So the result should shows the first date after the last empty stock grouped by ArticleID. ArticleID 2 didn't had a 0 point, so the first stock date is shown.
I need a result set that can be joined with other queries. So a Stored Procedure does not work for me.
select ArticleID,stockdate from
(
select t.ArticleID, t.stockdate, ROW_NUMBER() Over (partition by t.articleid order by v.articleid desc, stockdate) rn
from yourtable t
left join
(
select ArticleID, MAX(stockdate) as msd from yourtable t1
cross apply (select sum(stock) as stockrt from yourtable where stockdate<=t1.stockdate and ArticleID=t1.ArticleID) rt
where stockrt = 0
group by articleid
) v
on t.ArticleID = v.ArticleID
and t.stockdate>v.msd
) v
where rn=1