Subtract aggregate of only certain rows from only other certain rows in the same table? - sql

product saletype qty
-----------------------------
product1 regular 10
product1 sale 1
product1 feature 2
I have a sales table as seen above, and products can be sold 1 of 3 different ways (regular price, sale price, or feature price).
All sales regardless of type accumulate into regular, but sale and feature also accumulate into their own "saletype" also. So in the above example, I've sold 10 products total (7 regular, 1 sale, 2 feature).
I want to return the regular quantity minus the other two columns as efficiently as possible, and also the other saletypes too. Here is how I am currently doing it:
create table query_test
(product varchar(20), saletype varchar(20), qty int);
insert into query_test values
('product1','regular',10),
('product1','sale',1),
('product1','feature',2)
select
qt.product,
qt.saletype,
CASE WHEN qt.saletype = 'regular' THEN sum(qt.qty)-sum(lj.qty) ELSE sum(qt.qty) END as [qty]
from
query_test qt
left join
(
select product, sum(qty) as [qty]
from query_test
where saletype in ('sale','feature')
group by product
) lj on lj.product=qt.product
group by
qt.product, qt.saletype;
...which yields what I am after:
product saletype qty
-----------------------------
product1 feature 2
product1 regular 7
product1 sale 1
But I feel like there has to be a better way than essentially querying the same information twice.

You can use the window function sum and some arithmetic to do this.
select product,
saletype,
case when saletype='regular' then 2*qty-sum(qty) over(partition by product)
else qty end as qty
from query_test
This assumes there is atmost one row for saletype 'regular'.

Related

Select Duplicate SKU's and put corresponding prices into new adjacent columns

I have the following sql table - with duplicate SKU's - each with differing prices which represent bulk buy discounts:
SKU
Price
SKU1
$10.00
SKU2
$12.00
SKU2
$9.00
SKU1
$10.50
SKU2
$11.20
How can I use a SQL select statement to get the following output in the table below? Unique SKU's with the prices in new columns - prices high to low in the price columns left to right:
SKU
Price1
Price2
Price3
SKU1
$10.50
$10.00
SKU2
$12.00
$11.20
$9.00
My real-world data is for InCatalogue software which I use to bulk update prices in our printed catalogue in Adobe InDesign. The duplicate SKUs with differing prices represent bulk buy discounts. The InCatalogue software uses the identifier (SKU) to update tagged prices/text with the data from whichever column you specify it should look for (Price1, Price2 or Price3).
There is not always the same number of duplicate SKU's - e.g. Some SKU's don't have any bulk buy discounts, hence there would only be a price in column "Price1". Also, my real data actually has up to 4 duplicate SKU's, and I also have to add GST/VAT inclusive prices into additional columns - however, this is simple and would/could be a simple table update after this transforming of data is done - unless this can simply be calculated at the same time? (Resulting in Price1 exGST, Price1 incGST, Price2 exGST, Price2 incGST etc)
If you know the maximum number of prices, you can use row_number() and conditional aggregation:
select sku,
max(case when seqnum = 1 then price end) as price_1,
max(case when seqnum = 2 then price end) as price_2,
max(case when seqnum = 3 then price end) as price_3
from (select t.*,
row_number() over (partition by sku order by price) as seqnum
from t
) t
group by sku;
Note: This puts the prices in ascending order. It is not clear what ordering you might actually want, if any.

How to calculate the ratio of records based on values of two columns distinctly with the inner join of another table?

I'm developing a new analyst feature for an internal tool my company will (hopefully if I do well) use.
For simplicity sake, let's say we have
CREATE TABLE Products (
ProductID varchar,
Description varchar,
....
);
and
CREATE TABLE Orders (
ProductID varchar,
Bought date,
Returned date,
....
);
The tables would look something like this:
Products
ProductID
Description
SPO00
Sports product 1
SPO01
Sports product 2
SPO02
Sports product 3
ELE00
Electronics product 1
ELE02
Electronics product 2
Orders
ProductID
Bought
Returned
ELE00
2021-01-05
2021-01-07
SPO00
2021-01-01
NULL
SPO00
2021-01-05
2021-01-08
SPO00
2021-01-08
NULL
SPO01
2021-01-10
NULL
SPO01
2021-01-15
NULL
SPO02
2021-01-18
2021-01-20
I'd like to make a request to our DB and retrieve the description of specific products, and the percentage of bought products that are eventually returned.
I'd would also like to add specific parameters to the query, for example select only orders from beginning of the year as well as only the products from a specific department, for example.
So, it would looks something like this:
Description
ratio returned
Sports product 1
0.33
Sports product 2
0.00
Sports product 3
1.0
So, the products table might have product lines of electronics and sports and ProductID would be ELE00-ELE05 and SPO00-SPO03, respectively.
The above table is grabbing all products that have ProductID with SPO prefix and getting that specific products bought and returned ratio.
I've only been able to get the specific products, but the returned ratio is the same for each row. I think because its not doing the ratio calculation for each distinct product. I think its doing one overall ratio calculation and displaying that for each product.
Here is the query I've tried.
SELECT DISTINCT Product.Description, (CAST((SELECT DISTINCT COUNT(*) FROM Orders WHERE(ProductID like 'SPO%' AND Returned > '2021-01-01') AS FLOAT)) / (CAST((SELECT DISTINCT COUNT(*) FROM Orders WHERE (ProductID like 'SPO%' AND Bought > '2021-01-01') AS FLOAT)) AS returnedRatio
FROM Product INNER JOIN
Orders ON Orders.ProductID = Product.ProductID
I'm thinking I might need to do a nested query to get the ratios for each product and then get the description?
All help would be greatly appreciated because I've never done very complex queries so I'm still learning.
Does this work for you?
I used a case expression inside the count() function to count the number of returned products.
The * 1.0 turns the integer division into a decimal division without explicitly casting.
Sample data
CREATE TABLE Products (
ProductID nvarchar(5),
Description nvarchar(50)
);
insert into Products (ProductId, Description) values
('SPO00', 'Sports product 1'),
('SPO01', 'Sports product 2'),
('SPO02', 'Sports product 3'),
('ELE00', 'Electronics product 1'),
('ELE02', 'Electronics product 2');
CREATE TABLE Orders (
ProductID nvarchar(5),
Bought date,
Returned date
);
insert into Orders (ProductID, Bought, Returned) values
('ELE00', '2021-01-05', '2021-01-07'),
('SPO00', '2021-01-01', NULL),
('SPO00', '2021-01-05', '2021-01-08'),
('SPO00', '2021-01-08', NULL),
('SPO01', '2021-01-10', NULL),
('SPO01', '2021-01-15', NULL),
('SPO02', '2021-01-18', '2021-01-20');
Solution
select p.Description,
count(case when o.Returned is not null then 1 end) as ReturnCount,
count(1) TotalCount,
count(case when o.Returned is not null then 1 end) * 1.0 / count(1) as ReturnRatio
from Products p
join Orders o
on o.ProductID = p.ProductID
where p.ProductID like 'SPO%'
and o.Bought >= '2021-01-01'
group by p.Description;
Result
Description ReturnCount TotalCount ReturnRatio
---------------- ----------- ---------- --------------
Sports product 1 1 3 0.333333333333
Sports product 2 0 2 0
Sports product 3 1 1 1
Fiddle to see things in action.

SQL Max (Quantity*ProductPrice)

I am trying to answer the question of which product ID and ProductName brought in more revenue than the average revenue earned from a product in the store.
I have the following code:
Select ProductName, SupplierName, MAX(Quantity*ProductPrice) as TotalRev
From Products
Where MAX(TotalRev) > AVG(TotalRev)
Yet this results in an error.
Sample Data
ProductID ProductName SupplierName ProductType Quantity ProductPrice
10001 GreenJacket GAP Jackets 100 $10
10002 StarEarrings Oldnavy Accessories 200 $5
10003 YellowDress BRP Dress 150 $10
Ideally, I would want the code to spit out the ProductID and Product name where the product brought in more revenue that the average revenue.
You need a having clause and a subquery:
Select ProductId, ProductName,
SUM(Quantity*ProductPrice) as TotalRev
From Products
group by ProductId, ProductName
having SUM(Quantity*ProductPrice) >= (select avg(revenue)
from (select sum(p2.quantity * p2.ProductPrice) as revenue
from products as p2
group by p2.ProductId, p2.ProductName
) as p3
);
I would advise you to run the subquery in the having clause so that you fully understand what it is doing.

SQL Reconcillation Query

Need assistance with SQL Query which can reconcile multiple entries (Buy/Sell) from one table to single line entries, tracking the amount bought and sold in Qty and Qty Left Columns:
I have a table as follows:
CREATE TABLE [dbo].[Trades(
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[ExecId] [varchar](35) NULL,
[Side] [varchar](6) NULL,
[Symbol] [varchar](35) NULL,
[LastQty] [varchar](35) NULL,
[LastPrice] [varchar](25) NULL,
[LeftQty] [varchar](35) NULL,
[Date] [varchar](35) NULL
)
with Entries:
Id Side Symbol Qty LastPrice LeftQty Date
1 Buy ABC 100 10.00 0 1/1/2011
2 Sell ABC 100 12.00 0 1/1/2011
3 Sell XYZ 200 8.00 0 1/1/2011
4 Buy XYZ 100 7.00 100 1/1/2011
How can I query table to produce a reconcillation report from the previous data as follows:
Id Side Symbol EntQty EntPrice EntQty EntLeft ExtSide ExtQty ExtPrice ExtLeft
1 Buy ABC 100 10.00 100 0 Sell 100 12.00 0
2 Sell XYZ 200 8.00 200 0 Buy 100 7.00 100
I need to combine opposite buy/sell entries onto the same line and then track the amount (Qty) remaining if the Buy Qty does not equal the Sell Qty
I assume that you can have 1 sell entry and 1 buy entry and always both. If you can have only one of them, you need to use a left or right join depending which one is always present.
The Id can't be returned as you have more than one and you don't have any criteria to select one of them.
EDITED: We obtain for each symbol:
For boughts: total quantity, average price and the left quantity
For sells: total quantity, average price and the left quantity
The remains quantity (boughts total left quantity - sells total left quantity)
If you want an entry for each different pair buy-sell, you would need something to join the pair of entries (some common field). As you haven't got any field to join them, I think it is no possible to do on this way.
You can obtain all the info for each symbol on a single row, as the query does.
SELECT s.Symbol as Symbol,
b.SQty as EntQty, b.APrice as EntPrice, b.SLeft as EntLeft,
s.SQty as ExtQty, s.APrice as ExtPrice, s.SLeft as ExtLeft,
b.Qty - s.Qty as Remain
FROM
(SELECT Symbol,
sum(Qty) as SQty, avg(Price) as APrice, sum(LeftQty) as SLeft
FROM Trades WHERE Side = 'Sell' GROUP BY Symbol) s
INNER JOIN
(SELECT Symbol,
sum(Qty) as SQty, avg(Price) as APrice, sum(LeftQty) as SLeft
FROM Trades WHERE Side = 'Buy' GROUP BY Symbol) b
ON s.Symbol = b.Symbol
The easiest would be:
Group data by symbol and side,
Do a self join on the result set on the results
For example:
WITH DATA AS
(
SELECT Symbol, Side, Sum(EntPrice), Sum(EntLength)
FROM Trades
GROUP BY Symbol, Side
)
SELECT Symbol, -- Calculation goes here
FROM DATA Sell
JOIN DATA Buy ON Sell.Symbol = Buy.Symbol
WHERE Sell.Side = SELL AND Buy.Side = BUY
If there is not always a buy and sell line for each symbol, perform a cross join and handle nulls properly in the calculations

MySQL - Finding out Balancing Figure From 2 Tables

I have 2 tables like this:
Stock Table
product_id bigint(20)
qty float
Sales Table
product_id bigint(20)
qty float
Sample Data
Stock Table
product_id---qty
1---10
2---11
3---20
4---50
1---10
3---10
Sales Table
product_id---qty
1---2
2---5
3---20
4---40
1---7
I want the following Output after running the Query
product_id---qty
1---11
2---6
3---10
4---10
Well, as spender ask I am trying to more clear the situation.
First of All, let's think that I store
10 quantity of product 1
11 quantity of product 2
20 quantity of product 3
50 quantity of product 4
10 quantity of product 1 (now I have total 20 of product 1)
10 quantity of product 3 (now I have total 30 of product 3)
Secondly, let's think that I sell
2 quantity of product 1
5 quantity of product 2
20 quantity of product 3
40 quantity of product 4
7 quantity of product 1 (now I have sold total 9 of product 1)
Thirdly, I want to know how much stock is now in my hand
11 quantity of product 1 (20-9 = 11)
6 quantity of product 2 (11-5 = 6)
10 quantity of product 3 (30-20 = 10)
10 quantity of product 4 (50-4 = 10)
My Question is: To find out this stock what is the Query?
Thanks in Advance for answering my question.
This answer works in Oracle - don't have MySql so can't test there
select product_id, sum(qty) from
(
select product_id, qty from stock
union all
select product_id, (-1 * qty) from sales
) as a
group by prod
You question is lacking detail and looks like it might even contain typos in the presented data. I'm going to make the assumption you are trying to calculate the diff between stock quantities and sales quantities, despite your data not actually supporting this (!!!). It looks like you require the following:
select
st.product_id,
sto.qty-st.qty
from
salesTable as st
join stockTable as sto on sto.product_id=st.product_id
Chris's answer is absolutely correct. But for the information I want to add this one which I found on NET.
SELECT tunion.product_id, (
(IFNULL((SELECT SUM(s.qty) FROM stock s WHERE s.product_id=tunion.product_id),0))-
(IFNULL((SELECT SUM(p.qty) FROM sales p WHERE p.product_id=tunion.product_id),0)))
AS quantity
FROM (SELECT DISTINCT s.product_id FROM stock s
UNION ALL SELECT DISTINCT p.product_id FROM sales p)
AS tunion GROUP BY tunion.product_id