I have a table listed below and want to calculate new stock. initially new stock is 0
id qty price operation newstock
1 20 23 buy
2 10 12 sale
3 15 14 buy
4 6 13 buy
and so on
want output like- in case of buy- newstock+qty
and in case of sale- newstock-qty
id qty price operation newstock
1 20 23 buy 23 (eg- 0+23= 23)
2 10 12 sale 13 (previous row 23-10)
3 15 14 buy 28 (previous row 13+15)
4 6 13 buy 32 ( previous row 28+6)
I used cross apply also but not getting result.
I think you want a cumulative sum:
select t.*,
sum(case when operation = 'buy' then qty else -qty end) over (order by id) as newstock
from t
Related
So, I am new to postgresql. my data is as follows:
PRODUCT WKnum SALES
HAMMER 1 17
HAMMER 2 20
HAMMER 3 17
HAMMER 4 10
HAMMER 5 12
HAMMER 6 13
HAMMER 7 2
HAMMER 8 25
SINK 1 25
SINK 2 20
SINK 3 9
SINK 4 7
SINK 5 24
SINK 6 16
SINK 7 10
SINK 8 16
BUCKET 1 22
BUCKET 2 2
BUCKET 3 10
BUCKET 4 24
BUCKET 5 9
BUCKET 6 20
BUCKET 7 9
BUCKET 8 21
I would then like an outcome like the below:
PRODUCT BEST_CONSEC_4WEEKS BEST_CONSEC_4WEEKS_SLS
HAMMER 1-4 64
SINK 5-8 66
BUCKET 3-6 63
Where "BEST_CONSEC_4WEEKS" is a character string that tells the actual week numbers with the highest sum of sales over a consecutive 4 week period. And "BEST_CONSEC_4WEEKS_SLS" provides the total units sold for that product during the weeks identified above. Database-specific functions must be avoided.
The following piece of code was my attempt, but it is not working as I expected.
SELECT PRODUCT,
CASE WHEN Wknum IN ‘1 - 4’:: INTETER AS BEST_CONSEC_4WEEKS,
SUM (CASE WHEN Wknum IS BETWEEN ‘1 AND 4’::INTEGER THEN SALES ELSE 0 END) OR
SUM (CASE WHEN Wknum IS BETWEEN ‘5 AND 8’::INTEGER THEN SALES ELSE 0 END)
SUM (CASE WHEN Wknum IS BETWEEN ‘3 AND 6’::INTEGER THEN SALES ELSE 0 END) AS BEST_CONSEC_4WEEKS_SLS
FROM TABLE1
Can anyone please tell me what I am doing wrong? Thanks
You can use window functions with frames as follows:
with u as
(select PRODUCT,
WKnum,
sum(SALES) over(partition by PRODUCT order by WKnum rows between current row and 3 following) as BEST_CONSEC_4WEEKS_SLS
from TABLE1),
v as
(select *, rank() over(partition by PRODUCT order by BEST_CONSEC_4WEEKS_SLS desc) as r
from u)
select PRODUCT,
concat(wknum, '-', wknum + 3) as BEST_CONSEC_4WEEKS,
BEST_CONSEC_4WEEKS_SLS
from v where r = 1
fiddle
id item_name cust_id
1 Rolex 5
2 Diamond 33
3 Hublop 1
4 Ring 9
5 Ruby 13
6 Rolex 33
7 Hublop 29
8 Ring 17
9 Belt 21
10 Diamond 9
12 Belt 33
13 Hublop 9
14 Brooch 9
From these table I have to write a query to find those cust_id who have buy all three 'diamond,brooch,ring'
without using intersection ( IN clause will also not work)
You can use sum with a case statement for each item to get how many of that item the client has bought, then filter only customers that have bought at least one of each type of product:
select cust_id from
(select cust_id,
sum(case when item_name = 'Diamond' then 1 else 0 end) as cntDiamond,
sum(case when item_name = 'Brooch' then 1 else 0 end) as cntBrooch,
sum(case when item_name = 'Ring' then 1 else 0 end) as cntRing
from table_name
group by cust_id) as t
where cntDiamond > 0 and cntBrooch > 0 and cntRing > 0
Fiddle
I have the following table
Cash_table
ID Cash Rates Amount
1 50 3 16
2 100 4 25
3 130 10 7
3 130 10 6
4 13 7 1.8
5 30 8 2.5
5 30 10 1
6 10 5 2
What I want as a result is to cumulate all the entries that have a Count(id)>1 like this:
ID New_Cash New_Rates New_Amount
1 50 3 16
2 100 4 25
3 130 10+10 130/(10+10)
4 13 7 1.8
5 30 8+10 30/(8+10)
6 10 5 2
So I only want to change the rows where Count(id)>1 and leave the rest like it was.
For the rows with count(id)>1 I want to sum up the rates and take the cash and divide it by the sum of the rates. The Rates alone aren't a problem since I can sum them up and group by id and get the desired result.
The problem is with the New_Amount column:
I am trying to do it with a case statement but it isn't working:
select id,
cash as new_cash,
sum(rates) as new_rates,
(case count(id)
when 1 then amount
else cash/sum(nvl(rates,null))
end) as new_amount
from Cash_table
group by id
As the cash value is always the same for an ID, you can group by that as well:
select id,
cash as new_cash,
sum(rates) as new_rates,
case count(id)
when 1 then max(amount)
else cash/sum(rates)
end as new_amount
from cash_table
group by id, cash
order by id
ID NEW_CASH NEW_RATES NEW_AMOUNT
---------- ---------- ---------- ----------
1 50 3 16
2 100 4 25
3 130 20 6.5
4 13 7 1.8
5 30 18 1.66666667
6 10 5 2
The first branch of the case expression needs an aggregate because you aren't grouping by amount; and the sum(nvl(rates,null)) can just be sum(rates). If you're expecting any null rates then you need to decide how you want the amount to be handled, but nvl(rates,null) isn't doing anything.
You can do the same thing without a case expression if you prefer, manipulating all the values - which might be more expensive:
select id,
cash as new_cash,
sum(rates) as new_rates,
sum(amount * rates)/sum(rates) as new_amount
from cash_table
group by id, cash
order by id
I've spent that last couple of days searching for a way to make a SQL query that searches the database and returns records where the SUM of the same ID's equal or grater then the value provided.
For this I've been using the W3schools database to test it out in the products table.
More so what I've been trying to do:
SELECT * FROM products
WHERE supplierid=? and SUM(price) > 50
in the "where supplier id" would loop through same suppliers and sum of their price higher than 50 in this case return the records.
In this case it would read supplier ID 1 then add the price of all that supplier 18+19+10=47 now 47 < 50 so it will not print those records at the end. Next supplier ID 2 22+21.35=43.35 and again would not print those records until the sum of price is higher than 50 it will print
I'm working with a DB2 database.
SAMPLE data:
ProductID ProductName SupplierID CategoryID Price
1 Chais 1 1 18
2 Chang 1 1 19
3 Aniseed 1 2 10
4 Chef Anton 2 2 22
5 Chef Anton 2 2 21.35
6 Grandma's 3 2 25
7 Uncle Bob 3 7 30
8 Northwoods 3 2 40
9 Mishi 4 6 97
10 Ikura 4 8 31
11 Queso 5 4 21
12 Queso 5 4 38
13 Konbu 6 8 6
14 Tofu 6 7 23.25
How about:
select * from products where supplierid in (
select supplierid
from products
group by supplierid
having sum(price) > 50
);
The subquery finds out all the supplierid values that match your condition. The main (external) query retrieves all rows that match the list of supplierids.
not tested, but I would expect db2 to have analytic functions and CTEs, so perhaps:
with
basedata as (
select t.*
, sum(t.price) over(partition by t.supplierid) sum_price
from products t
)
select *
from basedata
where supplierid = ?
and sum_price > 50
The analytic function aggregates the price information but does not group the resultset, so you get the rows from your initial result, but restricted to those with an aggregated price value > 50.
The difference to a solution with a subquery is, that the use of the analytic function should be more efficient since it has to read the table only once to produce the result.
I have tables as follow:
A deliveries
delveryid clientid deliverydate
1 10 2015-01-01
2 10 2015-02-02
3 11 2015-04-08
B items in deliveris
itemid deliveryid qty status
70 1 5 1
70 1 8 2
70 2 10 1
72 1 12 1
70 3 100 1
I need to add a column to my query that gives me the qty of each part in other deliveris of the same client.
meaning that for given data of client 10 and delivery id 1 I need to show:
itemid qty status qtyOther
70 5 1 10 //itemid 70 exists in delivery 2
70 8 2 10 //itemid 70 exists in delivery 2
72 12 1 0 //itemid 72 doesn't exists in other delivery of client 11
Since I need to add qtyOther to my existing qry i'm trying to avoid using Group By as it's a huge query and if I use SUM in select I will have to group by all items in select.
This is what I have so far:
Select ....., coalesce( SUM(a.qty) OVER (PARTITION BY a.itemid) ,0) AS qtyOther
FROM B b
LEFT JOIN A a USING
LEFT JOIN (other tables)
WHERE clientid=10 ....
This query gives me the total sum of qty per itemid for specific clientid, regardless of which delivery it is. How do I change it so it will consider the delivryid? I need something like:
coalesce( SUM(a.qty) OVER (PARTITION BY a.itemid) FROM B where deliveryid<>b.deliveryid ,0) AS qtyOther
Any suggestions how to do that?
Note: I can NOT change the condition in WHERE.
I think you just want to subtract out the total for the current delivery:
Select .....,
(coalesce( SUM(a.qty) OVER (PARTITION BY a.itemid), 0) -
coalesce( SUM(a.qty) OVER (PARTITION BY a.itemid, a.deliveryid), 0)
) as qtyOther