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

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.

Related

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.

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

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

How to join two tables with max value not greater than another value of column

Apologies for the confusing question title, but I'm not exactly sure how to describe the issue at hand.
I have two tables in Oracle 9i:
Pricing
-------
SKU
ApplicableTime
CostPerUnit
Inventory
---------
SKU
LastUpdatedTime
NumberOfUnits
Pricing contains incremental updates to the costs of each particular SKU item, at a specific Unix time. For example, if I have records:
SKU ApplicableTime CostPerUnit
------------------------------------
12345 1000 1.00
12345 1500 1.50
, then item 12345 is $1.00 per unit for any time between 1000 and 1500, and $1.50 for any time after 1500.
Inventory contains SKU, last updated time, and number of units.
What I'm trying to do is construct a query such that for each row in Inventory, I join the two tables based on SKU, I find the largest value for Pricing.ApplicableTime that is NOT greater than Inventory.LastUpdatedTime, get the CostPerUnit of that particular record from Pricing, and calculate TotalCost = CostPerUnit * NumberOfUnits:
SKU TotalCost
-----------------------------------------------------------------------------------
12345 (CostPerUnit at most recent ApplicableTime <= LastUpdatedTime)*NumberOfUnits
12346 <same>
... ...
How would I do this?
SELECT *
FROM
(select p.SKU,
p.ApplicableTime,
p.CostPerUnit*i.NumberOfUnits as cost,
row_number over (partition by p.SKU order by p.ApplicableTime desc) as rnk
from Pricing p
join
Inventory i on (p.sku = i.sku and i.LastUpdatedTime > p.ApplicableTime)
)
where rnk=1
select SKU, i1.NumberOfUnits * p1.CostPerUnit as TotalCost
from Inventory i1,
join (
select SKU, max(ApplicableTime) as ApplicableTime, max(i.LastUpdatedTime) as LastUpdatedTime
from Pricing p
join Inventory i on p.sku = i.sku
where p.ApplicableTime < i.LastUpdatedTime
group by SKU
) t on i1.sku = t.sku and i1.LastUpdatedTime = t.LastUpdatedTime
join Pricing p1 on p1.sku = t.sku and p1.ApplicableTime = t.ApplicableTime

Getting products from SQL query

I'm currently working on a proprietary shopping cart system and was having a few problems with getting products out with the correct pricing.
Basically my table structure is as follows:
Products table: (Only relevant columns are represented)
----------------------------------------------------
productid | product | descr | disporder| list_price|
----------------------------------------------------
1 name desc 1 0.00
2 name desc 4 0.00
3 name desc 2 2.45
Pricing table:
----------------------------------------
priceid | productid | price | variantid|
----------------------------------------
1 1 13.91 1
2 2 54.25 4
3 2 47.23 2
Variants Table:
-------------------------------
variantid | productid | active|
-------------------------------
1 1 Y
2 2 Y
3 2 Y
So, each product can have - and in most cases does have - multiple variants. My current SQL query I have managed to create thus far is:
SELECT
products.productid, product, descr, p.price, i.image_path
FROM
products
LEFT JOIN
pricing AS p
ON
p.variantid = (SELECT variantid FROM variants
WHERE productid = products.productid LIMIT 1)
LEFT JOIN
images_T AS i
ON
i.id = products.productid
GROUP BY
products.productid
ORDER BY
products.disporder
However, my problem arises when a product does not have a variant. If a product does not have a variant associated with it, the price will be in the list_price column of the products table. How would I go about performing a check to see if a product does indeed have a variant. If not, it should effectively bypass the variants table and get the pricing from list_price within the products table.
Yes, CASE is an option, or COALESCE:
SELECT
products.productid, product, descr,
COALESCE(products.list_price, p.price) AS price,
i.image_path
...
Just join both prices and when the first is NULL the other will be selected.
The simplest way is to use a CASE in the SELECT clause, like so:
SELECT
products.productid, product, descr,
CASE
WHEN p.price IS NULL
THEN products.list_price
ELSE p.price
END AS price,
i.image_path
[...]
Since you're left-joining on pricing/variants, p.price should reliably be NULL for products with no variants.
Hopefully that's what you meant by "bypassing" the variants table. :)
You can do a full join with variants table (which will ONLY give you producs which have variants), and then UNION it with a join of producs and pricing where there exists no varian (using AND NOT EXISTS (SELECT 1 from variants WHERE p.productid=v.productid and p.variantid =v.variantid)
Otherwise, use CASE on pricing.price

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