Calculating COGS to finish stock balance report SQL - sql

I have two source table as following: Purchase & Sale
purchase (incoming)
--------------+----------+-------+----------+--------------
inventory_id | quantity | price | Amount | timestamp
--------------+----------+-------+----------+--------------
A | 1 | $1.00 | $1.00 | 2020-02-01
B | 2 | $1.00 | $2.00 | 2020-02-02
C | 4 | $2.00 | $8.00 | 2020-02-03
--------------+----------+-------+----------+--------------
sale (outgoing)
--------------+----------+-------+----------+--------------
inventory_id | quantity | price | Revenue | timestamp
--------------+----------+-------+----------+--------------
A | 1 | $3.00 | $3.00 | 2020-02-04
B | 1 | $3.00 | $3.00 | 2020-02-05
C | 2 | $3.00 | $6.00 | 2020-02-05
C | 1 | $3.00 | $3.00 | 2020-02-07
--------------+----------+-------+----------+--------------
What I want to do is the balance report in the below format:
Balance Report (2020-02-02 to 2020-02-05)
--------------+-----------+-------------+-------------+---------------+-----------+------------+---------+------------+
inventory_id | Begin Qty | Begin Amount| Purchase Qty|Purchase Amount| Sale Qty | COGS Amount | End Qty | End Amount |
--------------+-----------+-------------+-------------+---------------+-----------+------------+---------+------------+
A | 1 | $1.00 | | | 1 | $1.00 | | |
B | | | 2 | $2.00 | 1 | $1.00 | $1.00 | $1.00 |
C | | | 4 | $8.00 | 2 | $4.00 | $2.00 | $4.00 |
--------------+-----------+-------------+-------------+---------------+-----------+------------+---------+------------+
Note: The last outgoing transaction is out of the Report time range (2-05/02/2020) then not showing on the report.
MY CURRENT SOLUTION:
Add one column 'COGS' in the Sale table
I have to calculate the COGS of all inventory_id in the current sale order
Then save the COGS to the server with other information of sale order
THE PROBLEM:
If there is any change of the past transactions in the Purchase or Sale order, the COGS column does not UPDATE.
I NEED HELP ON:
Case 1: Keep COGS Column in the Sale table
How to update the value in this column if pasts transactions changed?
Case 2: Remove COGS Column
Pls help me to write a query to calculate the Sale Amount column in the Balance Report (Moving average is ok)
It would be great if you could provide the query to calculate the Sale Amount column by FIFO, LIFO.
Thanks a lot.

I found the solution: "I need to update COGS unit price for every transaction"
Following is the main code to update COGS
You might need to change something to adapt your case.
I know it is not the best solution but for my case it is ok.
create procedure update_COGS
as
update Sale
set
Sale.price = b.Aprice
from
Sale a
left join (select code, SUM(quantity) as quantity, sum(amount) as amount, SUM(amount)/nullif(sum(quantity),0) as Aprice from Purchase group by code) b
on a.code = b.code

Related

SQL - How to get latest price based on effective date?

Fairly straight forward query that is eluding me.. how do I get the effective cost for each product based upon the latest effective date given 7-6-2020 as the effective date?
Price Table:
id | product_name | cost | effective_date
=======================================================
1 | Product A | 8.00 | 1-5-2020
1 | Product A | 9.50 | 1-6-2020
1 | Product A | 10.00 | 1-7-2020
2 | Product B | 4.00 | 5-6-2020
2 | Product B | 4.50 | 5-7-2020
Expected Result:
id | product_name | cost | effective_date
-----------------------------------------------
1 | Product A | 10.00 | 1-7-2020
2 | Product B | 4.00 | 5-6-2020
One method is a correlated subquery:
select t.*
from t
where t.effective_date = (select max(t2.effective_date)
from t t2
where t2.id = t.id and
t2.effective_date <= '2020-07-06'
);

How to query the Gross Revenue group by STORE, by item's CATEGORY for each days in year? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have SALES table of each days, its has an STOREID and the ITEMID with the DATE and GROSS
| DATE | STOREID | ITEMID | GROSS |
|------------ |--------- |-------- |------- |
| 2020-07-07 | STORE1 | ITEM1 | 10000 |
| 2020-07-07 | STORE2 | ITEM1 | 25000 |
| 2020-07-06 | STORE2 | ITEM3 | 15000 |
| 2020-07-06 | STORE3 | ITEM2 | 21000 |
The PRODUCT table show the category of the items, we have 5 items with 5 categories:
| ITEMID | CATEGORY |
|-------- |---------- |
| ITEM1 | A |
| ITEM2 | B |
| ITEM3 | C |
| ITEM4 | B |
| ITEM5 | D |
How can I select the revenue by storeid, itemid of each day with all of the category (if that day only sold category A, B then category C, D will show with gross is 0). Here the example of expected result when selecting the gross of July 7 for STORE1:
| DATE | STOREID | CATEGORY | GROSS |
|------------ |--------- |---------- |------- |
| 2020-07-07 | STORE1 | A | 10000 |
| 2020-07-07 | STORE1 | B | 0 |
| 2020-07-07 | STORE1 | C | 0 |
| 2020-07-07 | STORE1 | D | 0 |
I have tried:
SELECT distinct T.DATE, T.STOREID, P.CATEGORY, ISNULL(T.GROSS,0) AS GROSS
FROM PRODUCT P LEFT JOIN (
SELECT CONVERT(DATE, DATEID) AS DATE, STOREID, P.CATEGORY, convert(numeric(10,0), sum(S.GROSS)) AS GROSS
FROM SALES S join PRODUCT P on S.ITEMID = P.ITEMID
WHERE DATEID = '2020-07-07' and STOREID = 'STORE1'
GROUP BY P.CATEGORY, DATEID, STOREID
) T
ON P.CATEGORY = T.CATEGORY
The results I get is something like this:
| DATE | STOREID | CATEGORY | GROSS |
|------------ |--------- |---------- |------- |
| 2020-07-07 | STORE1 | A | 10000 |
| 2020-07-07 | STORE1 | B | 0 |
| NULL | NULL | C | 0 |
| NULL | NULL | D | 0 |
So when I execute the Query for others STORES and others days, how can I automated specify the correct value for the NULL value (like the expected result)
Thank you guys so much for your help!
Is this homework? It looks a bit like homework, so instead of writing you a query, I will give you a strategy to think about.
You will first have to generate a cartesian product of date, and category, and store. Then find the sales that apply to each combination of {date, category, store}.
In general, generating "all of the dates you care about" is easy with a calendar table, or tally table, but in your specific case you could also generate all the dates you need for the cartesian product by querying your sales table for the distinct dates. This solution won't always work, because what if you want an output row for a date where no sales happened?
A cartesian product in sql is generated using a cross join
So, the approach you want to take:
Get a set of all the dates you need in the output
Cross join that against the set of all categories you need in the output
Cross join that against the set of all stores you need in the output
Left join that to the sales table

SELECT effective price based on dates

I am currently working on a supermarket database design where I have to have retrieve the effective price of the product based on the dates.
For example, price of Product A is $9.50 and it will be $10 effective from 1 July. However, this month is still June, so the price of Product A will still be the original price which is $9.50
The problem that I am facing is I am not able to select only one record from each product but all of them.
I am currently using SQL Server.
Price Table:
product_id | product_name | price | effective_date
=======================================================
1 | Product A | 8.00 | 1-5-2020
1 | Product A | 9.50 | 1-6-2020
1 | Product A | 10.00 | 1-7-2020
2 | Product B | 4.00 | 5-6-2020
2 | Product B | 4.50 | 5-7-2020
Codes:
SELECT Product.id, Product.product_name,Price_Table.price, Price_Table.effective_date,
(select top 1 price from Price_Table
where Price_Table.product_id=Product.id and getdate()>= effective_date
order by effective_date desc) 'Latest Price'
FROM Price_Table, Product
WHERE
Product.id=Price_Table.product_id
Result:
id | product_name | price | effective_date | Latest Price
----------------------------------------------------------------
1 | Product A | 8.00 | 1-5-2020 | 9.50
1 | Product A | 9.50 | 1-6-2020 | 9.50
1 | Product A | 10.00 | 1-7-2020 | 9.50
2 | Product B | 4.00 | 1-6-2020 | 4.00
2 | Product B | 4.50 | 1-7-2020 | 4.00
Expected Result:
id | product_name | price | effective_date | Latest Price
----------------------------------------------------------------
1 | Product A | 9.50 | 1-6-2020 | 9.50
2 | Product B | 4.00 | 1-6-2020 | 4.00
Based on the result, it shows all the records which is wrong. Expected result is the one result I hope to
get.
Can anyone help me with this? Thanks!
You can use cross apply:
SELECT p.*, pt.*
FROM Product p OUTER APPLY
(SELECT TOP (1) pt.*
FROM Price_Table pt
WHERE p.id = pt.product_id AND pt.effective_date <= GETDATE()
ORDER BY pt.effective_date DESC
) pt;

GET DATA FROM TXT SUM GROUP BY AND SUBTRACT

Trying to get data from txt file which contains buys and sells like in the format below.
I want to group by items and subtract each other.
I made three queries like totalin and totalout and stock but when I subtract out from in, some items are missing which has not been sold.
This is the data table
+------+---------+--------+
| TYPE | ITEM | AMOUNT |
+------+---------+--------+
| BUY | APPLE | 100 |
| BUY | ORANGE | 100 |
| BUY | APPLE | 200 |
| BUY | ORANGE | 200 |
| SELL | APPLE | 50 |
| SELL | APPLE | 50 |
| SELL | ORANGE | 100 |
| SELL | ORANGE | 100 |
| BUY | COCONUT | 50 |
| SELL | BANANE | 30 |
+------+---------+--------+
I want this output
+---------+--------+
| ITEM | AMOUNT |
+---------+--------+
| APPLE | 200 |
| BANANE | -30 |
| COCONUT | 50 |
| ORANGE | 100 |
+---------+--------+
I made 3 queries for the result that i want, but unfortunately I am stuck.
Here is my queries
QUERY 1 TOTAL IN:
SELECT DATA.TYPE, DATA.ITEM, Sum(DATA.AMOUNT) AS TOTALIN
FROM DATA
GROUP BY DATA.TYPE, DATA.ITEM
HAVING (((DATA.TYPE)="BUY"));
QUERY 2 TOTAL OUT:
SELECT DATA.TYPE, DATA.ITEM, Sum(DATA.AMOUNT) AS TOTALOUT
FROM DATA
GROUP BY DATA.TYPE, DATA.ITEM
HAVING (((DATA.TYPE)="SELL"));
QUERY 3 STOCK:
SELECT DATA.ITEM, [BUY]![TOTAL_IN]-[SELL]![TOTAL_OUT] AS STOK
FROM (DATA INNER JOIN BUY ON DATA.ITEM = BUY.ITEM) INNER JOIN SELL ON DATA.ITEM = SELL.ITEM
GROUP BY DATA.ITEM, [BUY]![TOTAL_IN]-[SELL]![TOTAL_OUT];
How can I made a query which shows the rest as stock.
Many thanks.
You can sum in one go like:
SELECT ITEM,
Sum(iif(data.type = "BUY", AMOUNT, -AMOUNT)) AS Stock
FROM DATA
GROUP BY ITEM;
You can think of SELL as -ve and BUY as +ve Amount.
Then the query becomes as follows
select item
,sum(case when type='BUY' then Amount
when type='SELL' then -Amount
end) as Amount
from data_table
group by item
In MsAccess, you can apply an if-logic block using the iif function and run the query in one step as below.
SELECT item,
SUM(iif ([type] = "SELL", (-1 * Amount), Amount)) as amounts
FROM data
GROUP BY item

Calculating Weighted Average for Price and Grouping by Item Type

I have a table in Access that tracks prices for certain products for each store. The table looks like this:
Date | Store | Item | SalesPounds | CompanyPrice
1/1/2016 | Store A | Product A | 1,000 | $5.00
1/1/2016 | Store A | Product B | 2,000 | $4.65
1/1/2016 | Store B | Product A | 5,000 | $7.56
1/1/2016 | Store B | Product B | 3,000 | $1.65
I would like to calculate the weighted average of CompanyPrice and then Group them by the products to look something like this:
Date |Item | SalesPounds | CompanyPrice
1/1/2016 | Product A | 6,000 |$7.13
1/1/2016 | Product B | 5,000 |$2.85
The query I am currently using is
SELECT [Date], [Item], Sum([SalesPounds]) as SumOfPounds, Sum([CompanyPrice]) as SumOfPrice
FROM MyTableName
GROUP BY [Date], [Item];
The following query should calculate the weighted average:
SELECT [Date],
Sum([SalesPounds]*[CompanyPrice]) / Sum([SalesPounds]) as WeightedAvg
FROM MyTableName
GROUP BY [Date];