I have two tables:
Sales:
SaleID | DayNumber | Quantity | ProductID
1 | 1 | 10 | 1
2 | 1 | 150 | 4
3 | 1 | 70 | 6
4 | 2 | 30 | 2
5 | 2 | 40 | 3
6 | 2 | 45 | 5
7 | 2 | 15 | 8
and Products:
ProductID | Price
1 | 12
2 | 52
3 | 643
4 | 42
5 | 75
6 | 53
7 | 2
8 | 7
So I wanna do get some results, but I have no idea how can I do them. I want to calculate for example the sum of the sold products for days 2,3 and 4. And also the average earnings for each day.
i think you need this simple sum with join query
create table #sales
(id int not null identity(1,1),
DayNUmber int,
Quantity int,
ProductID int)
create table #Products(
id int not null identity(1,1),
Price money
)
insert #sales
values
(1,10,1),
(1,150,4),
(1,70,6),
(2,30,2),
(2,40,3),
(2,45,5),
(2,5,8);
insert #Products
values
(12),
(52),
(643),
(42),
(75),
(53),
(2),
(5);
select
sum(s.Quantity*p.Price) as [sum],
s.DayNumber from #sales s inner join #Products p
on s.ProductID=p.id where s.DayNumber in (2,3)
group by s.DayNUmber
Join on common ID.
Take sum of Quantity * Price.
Group by Day and filter as needed.
SELECT
SUM(Quantity*Price)
,DayNumber
FROM Sales s
INNER JOIN PRODUCT p ON p.ProductID = s.ProductID
WHERE DayNumber IN(2,3,4)
GROUP BY DayNumber
To make this work you need to JOIN the two tables in your query. You can then use SUM to calculate the sum of the sold products and earnings. To filter for days 2, 3, and 4 you can use IN in your WHERE clause.
SELECT S.DayNumber, SUM(S.Quantity) AS 'Products Sold', SUM(S.Quantity * P.Price) AS 'Total Earnings'
FROM Sales AS S JOIN Products AS P ON S.ProductID = P.ProductID
WHERE S.DayNumber IN (2, 3, 4)
GROUP BY S.DayNumber
You need AVG per day and Total Sale per day. Filter as per the days required
SELECT SUM(p.Price * s.Quantity) TotalsalePerday, AVG(p.Price * s.Quantity) AvgsalePerday ,s.DayNumber from SO_Products p
INNER JOIN SO_Sales s ON p.ProductID = s.ProductID
GROUP BY DayNumber
ORDER BY DayNumber
/------------------------
OUTPUT
------------------------/
TotalsalePerday AvgsalePerday DayNumber
--------------- ------------- -----------
10130 3376 1
30760 7690 2
(2 row(s) affected)
Related
Let's say I have two tables. One is the orders table and the other is a price table giving the price of an item w.r.t. the number of items ordered.
The meaning of the test_price table is "up-to count items(inclusive) the cost per item is price". So 0-50 items cost 1.22 per item. 51-100 cost 1.20 per item.
table test_price
id | count | price
----+-------+-------
1 | 50 | 1.22
2 | 100 | 1.20
3 | 150 | 1.19
4 | 200 | 1.18
5 | 300 | 1.10
table test_orders
id | count
----+-------
1 | 12
2 | 50
3 | 65
4 | 155
5 | 400
So this means that order 1 for 12 items should be priced at 1.22 per item.
Order 5 should be priced at 1.10 per item.
I can get the price for a single order with
SELECT price FROM test_prices WHERE
count >= (SELECT count FROM test_orders WHERE id = 1)
ORDER BY count ASC LIMIT 1;
I would like to create a view that shows the orders with unit price and total price as columns
Join the tables on the count columns applying your conditions:
with cte as (select max(count) maxcount from test_price)
select
o.*, o.count * p.price total_price
from test_orders o inner join test_price p
on p.count = coalesce(
(select min(count) from test_price where o.count <= count),
(select maxcount from cte)
)
order by o.id;
See the demo.
Results:
| id | count | total_price |
| --- | ----- | ----------- |
| 1 | 12 | 14.64 |
| 2 | 50 | 61 |
| 3 | 65 | 78 |
| 4 | 155 | 182.9 |
| 5 | 400 | 440 |
I think your test_prices table is not quite right. I think it should be:
id | count | price
----+-------+-------
1 | 1 | 1.22
2 | 100 | 1.20
3 | 150 | 1.19
4 | 200 | 1.18
5 | 300 | 1.10
This says that for 1-99 quantity, the price is $1.22. For 100-149, the price $1.20, and so on.
With this structure, you can use a lateral join:
select o.*, p.price
from test_orders o left join lateral
(select p.*
from test_prices p
where p.count <= o.count
order by p.count desc
fetch first 1 row only
) p
on 1=1
The problem with your data is that price_table data is not all "up-to count", because the 5th row also means "up-to and beyond".
If you are able to add another row to price_table like (6, 10000, 1.10) then the solution is easy:
CREATE VIEW price_view AS
SELECT orders.id, orders.count, p.price, orders.count * p.price as total
FROM (
SELECT o.id, o.count, min(p.count) as pricebracket
FROM test_price p
LEFT JOIN test_orders o ON p.count >= o.count
GROUP BY o.id, o.count) orders
LEFT JOIN test_price p ON orders.pricebracket = p.count
ORDER BY orders.id
If you cannot get rid of this inconsistency in your data then you have to select maximum value first. So the query modifies like this:
CREATE VIEW price_view AS
WITH temptable as (SELECT max(p.count) as maxcount FROM test_price p)
SELECT orders.id, orders.count, p.price, orders.count * p.price as total
FROM (
SELECT o.id, o.count, min(p.count) as pricebracket
FROM test_price p
CROSS JOIN temptable
LEFT JOIN test_orders o ON p.count >=
(case when o.count > temptable.maxcount then temptable.maxcount else o.count end)
GROUP BY o.id, o.count) orders
LEFT JOIN test_price p ON orders.pricebracket = p.count
ORDER BY orders.id
I have the following tables
Table 1 : Product
id name
1 Bread
2 Bun
3 Cake
Table 2: Expense Items
product| quantity
1 | 100
2 | 150
3 | 180
1 | 25
2 | 30
Table 3: Income Items
product| quantity
1 | 100
2 | 150
3 | 180
1 | 25
2 | 30
Now I want the results like this
product | sum of quantity of expenseitem | sum of quantity of income item
1 | 125 | 125
2 | 180 | 180
3 | 180 | 180
What is the query to get this result ?
Thanks
You can try to use UNION ALL in a subquery with the condition in the aggregate function
Schema (PostgreSQL v9.6)
CREATE TABLE Product(
id int,
name varchar(50)
);
INSERT INTO Product VALUES (1,'Bread');
INSERT INTO Product VALUES (2,'Bun');
INSERT INTO Product VALUES (3,'Cake');
CREATE TABLE ExpenseItems(
product int,
quantity int
);
INSERT INTO ExpenseItems VALUES (1,100);
INSERT INTO ExpenseItems VALUES (2,150);
INSERT INTO ExpenseItems VALUES (3,180);
INSERT INTO ExpenseItems VALUES (1,25);
INSERT INTO ExpenseItems VALUES (2,30);
CREATE TABLE IncomeItems(
product int,
quantity int
);
INSERT INTO IncomeItems VALUES (1,100);
INSERT INTO IncomeItems VALUES (2,150);
INSERT INTO IncomeItems VALUES (3,180);
INSERT INTO IncomeItems VALUES (1,25);
INSERT INTO IncomeItems VALUES (2,30);
Query #1
SELECT p.id,
SUM(CASE WHEN grp = 1 THEN quantity END) SUMExpenseItems,
SUM(CASE WHEN grp = 2 THEN quantity END) SUMIncomeItems
FROM (
SELECT product, quantity,1 grp
FROM ExpenseItems
UNION ALL
SELECT product, quantity,2
FROM IncomeItems
) t1 JOIN Product p on p.id = t1.product
GROUP BY p.id;
| id | sumexpenseitems | sumincomeitems |
| --- | --------------- | -------------- |
| 1 | 125 | 125 |
| 2 | 180 | 180 |
| 3 | 180 | 180 |
View on DB Fiddle
Similar to #D-Shih's answer, PostgreSQL 9.4+ supports the FILTER() clause for conditional aggregation in place of CASE statements:
SELECT p.id,
SUM(quantity) FILTER (WHERE grp = 1) SUMExpenseItems,
SUM(quantity) FILTER (WHERE grp = 2) SUMIncomeItems
FROM
-- ...same union all query...
GROUP BY p.id
I am facing a problem with a query. My goal is to get all product names, unit of mass, quantity and number of pallets they are located in. The problem is with number of pallets of item.
QUERY:
SELECT "Product_Name"
, "Unit_of_Mass"
, SUM("Quantity_Per_UOM")
, Count(*) as "Number_Of_Pallet"
FROM
(select p.prod_desc as "Product_Name"
, s.quantity as "Quantity_Per_UOM"
, u.description as "Unit_of_Mass"
, s.container_id
, s.product_id
from wms_stock s
join wms_product p on p.product_id = s.product_id
join wms_uom u on p.uom_base_id = u.uom_id
)
group by "Product_Name", "Unit_of_Mass"
It almost works. The problem is I need to do some condition in Count(*) (that's what I think should be done). In table wms_stock I got product_id and container_id, and when in some row they are same it should count the number of pallets as 1 but still add the quantities.
So from first select:
Product_Name | Quantity | UnitOfMass | ContainerId | ProductId
A | 2 | kg | 10 | 11
A | 1 | kg | 10 | 11
B | 2 | kg | 11 | 12
I should get result
Product_Name | Quantity_Per_UOM | UnitOfMass | Number_Of_Pallet
A | 3 | kg | 1
B | 2 | kg | 1
You can try below condition in your select list -
COUNT(DISTINCT ContainerId || ProductId)
Just for your information, || is not an operator rather it is concatenation operator in Oracle. So i have just concat both the columns and picked up the distinct from them.
I have the following scheme (2 tables):
Customer (Id, Name) and
Sale (Id, CustomerId, Date, Sum)
How to select the following data ?
1) Best customer of all time (Customer, which has Max Total value in the Sum column)
For example, I have 2 tables (Customers and Sales respectively):
id CustomerName
---|--------------
1 | First
2 | Second
3 | Third
id CustomerId datetime Sum
---|----------|------------|-----
1 | 1 | 04/06/2013 | 50
2 | 2 | 04/06/2013 | 60
3 | 3 | 04/07/2013 | 30
4 | 1 | 03/07/2013 | 50
5 | 1 | 03/08/2013 | 50
6 | 2 | 03/08/2013 | 30
7 | 3 | 24/09/2013 | 20
Desired result:
CustomerName TotalSum
------------|--------
First | 150
2) Best customer of each month in the current year (the same as previous but for each month in the current year)
Thanks.
Try this for the best customer of all times
SELECT Top 1 WITH TIES c.CustomerName, SUM(s.SUM) AS TotalSum
FROM Customer c JOIN Sales s ON s.CustomerId = c.CustomerId
GROUP BY c.CustomerId, c.CustomerName
ORDER BY SUM(s.SUM) DESC
One option is to use RANK() combined with the SUM aggregate. This will get you the overall values.
select customername, sumtotal
from (
select c.customername,
sum(s.sum) sumtotal,
rank() over (order by sum(s.sum) desc) rnk
from customer c
join sales s on c.id = s.customerid
group by c.id, c.customername
) t
where rnk = 1
SQL Fiddle Demo
Grouping this by month and year should be trivial at that point.
How would you calc how many times a product is sold in average in a week or month, year.
I'm not interested in the Amount, but how many times a customer has bought a given product.
OrderLine
OrderNo | ProductNo | Amount |
----------------------------------------
1 | 1 | 10 |
1 | 4 | 2 |
2 | 1 | 2 |
3 | 1 | 4 |
Order
OrderNo | OrderDate
----------------------------------------
1 | 2012-02-21
2 | 2012-02-22
3 | 2012-02-25
This is the output I'm looking for
ProductNo | Average Orders a Week | Average Orders a month |
------------------------------------------------------------
1 | 3 | 12 |
2 | 5 | 20 |
You would have to first pre-query it grouped and counted per averaging method you wanted. To distinguish between year 1 and 2, I would add year() of the transaction into the grouping qualifier for distinctness. Such as Sales in Jan 2010 vs Sales in 2011 vs 2012... similarly, week 1 of 2010, week 1 of 2011 and 2012 instead of counting as all 3 years as a single week.
The following could be done if you are using MySQL
select
PreCount.ProductNo,
PreCount.TotalCount / PreCount.CountOfYrWeeks as AvgPerWeek,
PreCount.TotalCount / PreCount.CountOfYrMonths as AvgPerMonth,
PreCount.TotalCount / PreCount.CountOfYears as AvgPerYear
from
( select
OL.ProductNo,
count(*) TotalCount,
count( distinct YEARWEEK( O.OrderDate ) ) as CountOfYrWeeks,
count( distinct Date_Format( O.OrderDate, "%Y%M" )) as CountOfYrMonths,
count( distinct Year( O.OrderDate )) as CountOfYears
from
OrderLine OL
JOIN Order O
on OL.OrderNo = O.OrderNo
group by
OL.ProductNo ) PreCount
This is a copy of DRapp's answer, but coded for SQL Server (it's too big for a comment!)
SELECT PreCount.ProductNo,
PreCount.TotalCount / PreCount.CountOfYrWeeks AS AvgPerWeek,
PreCount.TotalCount / PreCount.CountOfYrMonths AS AvgPerMonth,
PreCount.TotalCount / PreCount.CountOfYears AS AvgPerYear
FROM (SELECT OL.ProductNo,
Count(*) TotalCount,
Count(DISTINCT Datepart(wk, O.OrderDate)) AS CountOfYrWeeks,
Count(DISTINCT Datepart(mm, O.OrderDate)) AS CountOfYrMonths,
Count(DISTINCT Year(O.OrderDate)) AS CountOfYears
FROM OrderLine OL JOIN [Order] O
ON OL.OrderNo = O.OrderNo
GROUP BY OL.ProductNo) PreCount