Calculate Weighted Average in sql for duplicate items - sql

TABLE
ITEM | SKU | QUANT | ITEM LANDING
-----+-------+---------+-----------------
ABC | A-B-C | 5 | 500
ABC | A-B-C | 10 | 400
DEF | D-E-F | 5 | 200
GHI | G-H-I | 6 | 300
JKL | J-K-L | 5 | 800
JKL | J-K-L | 10 | 600
RESULT
ITEM NAME | ITEM SKU | QUANT | Weighted Average
----------+-----------+--------+---------------------
ABC | A-B-C | 15 | 433.33
DEF | D-E-F | 5 | 200
GHI | G-H-I | 6 | 300
JKL | J-K-L | 15 | 666.66
I want to calculate weighted average for duplicate items
((first landing *qty)+(second landing *qty))/(sum(qty)

SELECT ITEMNAME, ITEMSKU, SUM(QUANT), SUM(QUANT * ITEM_LANDING) / SUM(QUANT)
FROM <YourTable>
GROUP BY ITEMNAME, ITEMSKU

Try this...
QUERY
SELECT item_name AS 'ITEM NAME',
item_sku AS ' ITEM SKU',
SUM(quant) AS 'QUANT',
(SUM(quant*item_landing)/sum(quant)) AS 'ITEM LANDING'
FROM items
GROUP BY item_name;
SQL FIDDLE

Related

SQL showing summary after each column value changes

I have sales data for branches. I want a SQL which will give me summary of sales data for each branchId as below, of course BranchId(s) are huge so I have to make it dynamic (I can't use Union). I am stuck how to add a summary row after every branch change dynamically.
+ ---------+--------+---------+-----------+
| BranchId | CashIn | CashOut | CardSales |
+ ---------+--------+---------+-----------+
| 1 | 1000 | 500 | 50 |
| 1 | 500 | 2500 | 100 |
| 1 | 1000 | 200 | 200 |
| Totals | 2500 | 3200 | 350 |
| 5 | 100 | 500 | 500 |
| Totals | 100 | 500 | 500 |
| 7 | 100 | 100 | 100 |
| 7 | 200 | 300 | 400 |
| Totals | 300 | 400 | 500 |
+ ---------+--------+---------+-----------+
A brute force method is to do the aggregation and then interleave the results:
select (case when is_base = 1 then to_char(BranchId)
else replace('Total ([BranchId])', '[BranchId]', BranchId)
end) as BranchId, CashIn, CashOut, CardSales
from ((select BranchId, CashIn, CashOut, CardSales, 1 as is_base
from t
) union all
(select BranchId, sum(CashIn), sum(CashOut), sum(CardSales), 0 as is_base
from t
group by BranchId
)
) t
order by t.BranchId, is_base desc;
Here is a db<>fiddle.

DB2 SQL, Calculate total on orders ready to ship

I'm trying to calculate the total value or all orders where we have all items in stock required to fill the order. In the example below, I want to select only the total value of order 100 only, since there is not enough inventory to fill order 200.
+-------+------+-------------+--------------+-------+
| Order | Item | Qty Ordered | Qty In Stock | Price |
+-------+------+-------------+--------------+-------+
| 100 | A | 10 | 25 | 1.00 |
+-------+------+-------------+--------------+-------+
| 100 | B | 15 | 50 | 2.00 |
+-------+------+-------------+--------------+-------+
| 100 | C | 30 | 75 | 3.00 |
+-------+------+-------------+--------------+-------+
| 200 | A | 5 | 25 | 1.00 |
+-------+------+-------------+--------------+-------+
| 200 | B | 100 | 50 | 2.00 | * Not enough stock to fill
+-------+------+-------------+--------------+-------+
| 200 | C | 35 | 75 | 3.00 |
+-------+------+-------------+--------------+-------+
How about:
select o.id, sum(o.qty_ordered * o.price) as total_value
from orders o
where o.id not in (
select id from orders where qty_ordered > qty_in_stock
)
group by o.id

SELECTing monthly order amounts and item subtotals in a single query with two tables

I have an Orders table in the form:
| id | service_fee_cents | grand_total_cents | created_at |
|----|-------------------|-------------------|---------------|
| 1 | 1400 | 10000 | Jan 21 2018 |
| 2 | 1000 | 10000 | Feb 16 2018 |
| 3 | 500 | 10000 | March 21 2018 |
| 4 | 500 | 10000 | March 20 2018 |
And an Items table in the form
| id | order_id | title | price_cents | quantity |
|----|----------|--------|-------------|----------|
| 1 | 1 | lorem | 2000 | 2 |
| 2 | 1 | ipsum | 2030 | 1 |
| 3 | 2 | pie | 4000 | 4 |
| 4 | 3 | cheese | 6000 | 2 |
| 5 | 3 | burger | 7000 | 1 |
| 6 | 4 | custar | 1000 | 1 |
And I'm trying to run a SQL query to get a result in the form
| month | total_service_fee | total_grand_total | total_subtotal |
|-----------|-------------------|-------------------|----------------|
|2017-11-01 | 42 | 1,610 | 610 |
|2017-12-01 | 30 | 19,912 | 1,912 |
|2018-01-01 | 179 | 1,413 | 413 |
|2018-02-01 | 165 | 2,910 | 910 |
|2018-03-01 | 1,403 | 10,727 | 1,727 |
I've managed to get the first three columns using this query:
SELECT
date_trunc('month', created_at)::date AS month,
SUM(service_fee_cents) / 100 AS total_service_fee,
SUM(grand_total_cents) / 100 AS total_grand_total
FROM orders
GROUP BY month ORDER BY month
How do I get the last one? In the app, I get the sum via the following Ruby code:
order_subtotal = order.items.map{|item| item.price * item.quantity}.reduce(:+)
Which basically takes all the order's items, multiplies price by quantity and adds the results.
This should be a good start:
SELECT Date_trunc('month', created_at) :: DATE AS month,
SUM(service_fee_cents) / 100 AS total_service_fee,
SUM(grand_total_cents) / 100 AS total_grand_total,
SUM(total_subtotal) / 100 AS total_subtotals
FROM orders o
join (SELECT order_id,
SUM(price_cents * quantity) total_subtotal
FROM items i
GROUP BY order_id) i
ON o.id = i.order_id
GROUP BY month
ORDER BY month
You can get there by just joining the Orders table to the Items table and generating a SUM of subtotals by month. This may however be a somewhat expensive query to run if there are thousands of items in each order like you said.
SELECT
date_trunc('month', created_at)::date AS month,
SUM(service_fee_cents) / 100 AS total_service_fee,
SUM(grand_total_cents) / 100 AS total_grand_total,
SUM(price_cents * quantity) / 100 AS sub_total
FROM Orders o
JOIN Items i ON i.order_id = o.id
GROUP BY month ORDER BY month
http://sqlfiddle.com/#!15/555a2/1

postgresql - Change single row to multiple rows

I have a table named payment_info, with the following records.
paymentid | customercode | previousbalance | paymentamount | remainingbalance
-----------------------------------------------------------------------------
PID0001 | CUST024 | 10000 | 2500 | 7500
PID0002 | CUST031 | 8500 | 3500 | 5000
PID0003 | CUST005 | 12000 | 1500 | 10500
Then what I want is to create a 3 rows per row of the above table.
I want my results to look like this.
Payment Group | Payment Line Item | Payment ID | Customer Code | Type | Amount
--------------------------------------------------------------------------------------------------
1 | 1 | PID0001 | CUST024 | PREVIOUS BALANCE | 10000.00
1 | 2 | | | PAYMENT AMOUNT | 2500.00
1 | 3 | | | REMAINING BALANCE | 7500.00
2 | 1 | PID0002 | CUST031 | PREVIOUS BALANCE | 8500.00
2 | 2 | | | PAYMENT AMOUNT | 3500.00
2 | 3 | | | REMAINING BALANCE | 5000.00
3 | 1 | PID0003 | CUST005 | PREVIOUS BALANCE | 12000.00
3 | 2 | | | PAYMENT AMOUNT | 1500.00
3 | 3 | | | REMAINING BALANCE | 10500.00
Here is the query I've started. But it did not return results same as above.
select row_number() over() as id,paymentid,customercode,'PREVIOUS BALANCE' as type,previousbalance from payment_info
union
select row_number() over() as id,'','','PAYMENT AMOUNT' as type,paymentamount from payment_info
union
select row_number() over() as id,'','','REMAINING BALANCE' as type,remainingbalance from payment_info
Is there other ways, where I will not use UNION Keyword? Cause in the real table, I will be using 30+ columns, querying thousands of records.
I also don't know how to create auto generated number (id) from payment group (per payment id) and Payment Line Item (per group).
thanks
version with whitespace (empty text)
The unnest function can do this for you.
And if you want the empty text then you can use this
SELECT ROW_NUMBER() OVER (ORDER BY paymentid) AS "group",
unnest(array[1, 2, 3]) AS "line item",
unnest(array[paymentid, '', '']) AS "paymentid",
unnest(array[customercode, '', '']) AS "customercode",
unnest(array['PREVIOUS BALANCE', 'PAYMENT AMOUNT', 'REMAINING BALANCE']) AS "type",
unnest(array[previousbalance, paymentamount, remainingbalance]) AS "amount"
FROM payment_info
ORDER BY 1, 2 ;
To get this
group | line item | paymentid | customercode | type | amount
-------+-----------+-----------+--------------+-------------------+--------
1 | 1 | PID0001 | CUST024 | PREVIOUS BALANCE | 10000
1 | 2 | | | PAYMENT AMOUNT | 2500
1 | 3 | | | REMAINING BALANCE | 7500
2 | 1 | PID0002 | CUST031 | PREVIOUS BALANCE | 8500
2 | 2 | | | PAYMENT AMOUNT | 3500
2 | 3 | | | REMAINING BALANCE | 5000
3 | 1 | PID0003 | CUST005 | PREVIOUS BALANCE | 12000
3 | 2 | | | PAYMENT AMOUNT | 1500
3 | 3 | | | REMAINING BALANCE | 10500
If you want to have, for example points or other text, or arrows in the empty text columns, you can do this easily with unnest.
You can control the 4 empty text values individually.
SELECT ROW_NUMBER() OVER (ORDER BY paymentid) AS "group",
unnest(array[1, 2, 3]) AS "line item",
unnest(array[paymentid, ' a', ' c']) AS "paymentid",
unnest(array[customercode, ' b', ' d']) AS "customercode",
unnest(array['PREVIOUS BALANCE', 'PAYMENT AMOUNT', 'REMAINING BALANCE']) AS "type",
unnest(array[previousbalance, paymentamount, remainingbalance]) AS "amount"
FROM payment_info
ORDER BY 1, 2 ;
to generate
group | line item | paymentid | customercode | type | amount
-------+-----------+-----------+--------------+-------------------+--------
1 | 1 | PID0001 | CUST024 | PREVIOUS BALANCE | 10000
1 | 2 | a | b | PAYMENT AMOUNT | 2500
1 | 3 | c | d | REMAINING BALANCE | 7500
2 | 1 | PID0002 | CUST031 | PREVIOUS BALANCE | 8500
2 | 2 | a | b | PAYMENT AMOUNT | 3500
2 | 3 | c | d | REMAINING BALANCE | 5000
3 | 1 | PID0003 | CUST005 | PREVIOUS BALANCE | 12000
3 | 2 | a | b | PAYMENT AMOUNT | 1500
3 | 3 | c | d | REMAINING BALANCE | 10500
It's a very flexible solution, you know.
It isn't necessary to always use union queries. Here for example you can use 3 rows and a cross join instead. This has the advantage of only a single pass over the source table.
drop table if exists Table1;
CREATE TABLE Table1
("paymentid" varchar(7), "customercode" varchar(7)
, "previousbalance" int, "paymentamount" int, "remainingbalance" int)
;
INSERT INTO Table1
("paymentid", "customercode", "previousbalance", "paymentamount", "remainingbalance")
VALUES
('PID0001', 'CUST024', 10000, 2500, 7500),
('PID0002', 'CUST031', 8500, 3500, 5000),
('PID0003', 'CUST005', 12000, 1500, 10500)
;
select
paymentid
, customercode
, rn
, typeof
, case when rn = 1 then previousbalance
when rn = 2 then paymentamount
when rn = 3 then remainingbalance
end as Amount
from Table1
cross join (select 1 rn , 'previousbalance' typeof
union all
select 2 , 'paymentamount'
union all
select 3, 'remainingbalance'
) rns
That data/query produces this result:
+----+-----------+--------------+----+------------------+--------+
| | paymentid | customercode | rn | typeof | amount |
+----+-----------+--------------+----+------------------+--------+
| 1 | PID0001 | CUST024 | 1 | previousbalance | 10000 |
| 2 | PID0001 | CUST024 | 2 | paymentamount | 2500 |
| 3 | PID0001 | CUST024 | 3 | remainingbalance | 7500 |
| 4 | PID0002 | CUST031 | 1 | previousbalance | 8500 |
| 5 | PID0002 | CUST031 | 2 | paymentamount | 3500 |
| 6 | PID0002 | CUST031 | 3 | remainingbalance | 5000 |
| 7 | PID0003 | CUST005 | 1 | previousbalance | 12000 |
| 8 | PID0003 | CUST005 | 2 | paymentamount | 1500 |
| 9 | PID0003 | CUST005 | 3 | remainingbalance | 10500 |
+----+-----------+--------------+----+------------------+--------+
Please then note that SQL isn't a "report writer" so blanks in columns for "layout" are not a good fit for SQL which wants to repeat information (like you see above in the result) so that you can sort and filter as needed.

calculating total sale with different prices

So I have a table which I am using to store data for my documents. Now I want to calculate my sale over some period and let's say I have table like this now:
| productID | price | quantity |
| 30 | 15 | 5 |
| 30 | 15 | 3 |
| 20 | 13 | 2 |
| 20 | 13 | 3 |
| 30 | 12 | 4 |
| 30 | 16 | 1 |
| 15 | 1 | 2 |
| 10 | 3 | 5 |
So I need a SQL command that will multiply the price and quantity for every row separate (because as you can see, for some products I have different prices e.g. where product id is 30) and then sum all those values.
This will give you total sales for each product
SELECT productID,
Sum(Price * quantity) AS Total_sales
FROM yourtable
GROUP BY productID