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 | | | |
+------+---------+------+----------+---------------+---------+------------------------+
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
+---------+--------+-----+---------+-------+-----------+-------+-----------+--------+
| 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
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.
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