I am a basic user of SQL but need to join 3 tables together to sow a) sales b) returns and c) profit
I currently have the following code
select * from (
select SUM(Return_Amount) , 'Return' as type, monthname(Return_Date) as month_
from returns
group by month_
union
select SUM(Order_Total_Cost) , 'Sales' as type, monthname(Order_Date) as month_
from sales
group by month_
union
select SUM(profit) as profit_ , 'Profit' as type, month_
from(
select sell_price-cost_price as profit , monthname(order_date) month_
from sales
join order_item
on order_item.order_No = sales.order_No
join returns
on returns.order_no = sales.order_No
join supplier
on supplier.Product_ID = order_item.Product_ID
) B group by month_
) A order by month_;
This is showing as below:
387 Return August
182 Sales August
867 Profit August
733 Return July
109 Sales July
646 Profit July
596 Return June
I want it to show with Return, Sales & Profit as separate columns instead of all types listed in one.
Any help would be greatly appreciated.
Thanks
Why not join them?
SELECT x.month_
, x.returns_
, y.sales_
, z.profit_
FROM
(SELECT SUM(Return_Amount) AS returns_
, monthname(Return_Date) AS month_
FROM RETURNS
GROUP BY month_) x
INNER JOIN
(SELECT SUM(Order_Total_Cost) AS sales_
, monthname(Order_Date) AS month_
FROM sales
GROUP BY month_) y ON x.month_ = y.month_
INNER JOIN
(SELECT SUM(profit) AS profit_
, month_
FROM
(SELECT sell_price-cost_price AS profit
, monthname(order_date) month_
FROM sales
INNER JOIN order_item ON order_item.order_No = sales.order_No
INNER JOIN RETURNS ON returns.order_no = sales.order_No
INNER JOIN supplier ON supplier.Product_ID = order_item.Product_ID) B
GROUP BY month_) z ON x.month_ = z.month_
You could turn the three unioned queries to subqueries and join them. This assumes that each subquery always produces one record per month.
Also: you probably want to join and month and year, in case your data spans over multiple years (which eventually happens in any live dataset). I would also recommend using numeric years and month (as returned by year() and month()), which would produce more efficient joins than month names.
select
r.month_name,
r.total_return_amount,
s.total_sales,
p.total_profit
from
(
select
year(return_date) yr,
month(return_date) mh,
monthname(return_date) month_name
sum(return_amount) total_return_amount,
from returns
group by
year(return_date),
month(return_date),
monthname(return_date)
) r
inner join (
select
year(order_date) yr,
month(order_date) mh,
sum(order_total_cost) total_sales
from sales
group by
year(order_date),
month(order_date)
) s on s.yr = r.yr and s.mh = r.mh
inner join (
select
year(order_date) yr,
month(order_date) mh,
sum(sell_price - cost_price) as total_profit ,
from sales
inner join order_item on order_item.order_no = sales.order_no
inner join returns on returns.order_no = sales.order_no
inner join supplier on supplier.product_id = order_item.product_id
group by
year(order_date),
month(order_date)
) p on p.yr = r.yr and p.mh = r.mh
Related
Make a report on the sales in 2015 of the products by categories (total value and
quantity sold). Also determine what% of the value of sales
for a given category represent the sales of each of the products in the category.
My query so far:
WITH sales AS
(SELECT t1.category_name
, t2.product_name
, (t3.unit_price*t3.quantity) Total_sales
, EXTRACT (YEAR FROM order_date) Year
FROM categories t1
INNER JOIN
products t2
ON t2.category_id=t1.category_id
INNER JOIN
order_details t3
ON t3.product_id=t2.product_id
INNER JOIN
orders t4
ON t4.order_id=t3.order_id
WHERE EXTRACT (YEAR FROM order_date) = '2015'
GROUP BY t1.category_name
, t2.product_name
, (t3.unit_price*t3.quantity)
, EXTRACT (YEAR FROM order_date)
ORDER BY 1
)
SELECT s.category_name
, s.product_name
, SUM (Total_sales)
FROM sales s
GROUP BY s.category_name
, s.product_name
ORDER BY 1
How to calculate %? Thank you
I think that you want window functions - if your database, that you did not specify, supports them:
SELECT
c.category_name
p.product_name
SUM(od.unit_price * od.quantity) as total_sales
1.0 * SUM(od.unit_price * od.quantity)
/ SUM(SUM(od.unit_price * od.quantity)) OVER(PARTITION BY c.category_id)
as category_sales_ratio
FROM categories c
INNER JOIN products t2 p ON p.category_id = c.ategory_id
INNER JOIN order_details od ON od.product_id = p.product_id
INNER JOIN orders o ON o.order_id = od.order_id
WHERE o.order_date >= '2015-01-01' AND o.order_date < '2016-01-01'
GROUP BY c.category_id, c.ategory_name, p.product_id, p.product_name
ORDER BY c.category_name, p.product_name
The window sum computes the total sales for the whole category, that you can divide the sales of the current product with.
Note that I changed your query in serveral ways:
meaningful table aliases make the query easier to write, read and maintain
filtering dates without transformation is much more efficient that using date functions
there is no need for a subquery
it is always a good idea to put the relevant primary keys in the GROUP BY clause (in case two different products or categories have the same name) - on the other hand, you also had additiona uneeded columns in that clause
I have Database table and trying to write query to find sold and not sold product list from one table.
Table is Below
Expecting Result
How do i get this result? i am using CTE to create Tamp table and with all services and then do left join but it dose give me only product sold in Feb, but i want all product with no sell too.
You can cross join the products and the dates, and then bring the table with a left join:
select
p.product,
t.quantity_sold,
d.yr,
d.mn
from (select distinct product from mytable) p
cross join (select distinct yr, mn from mytable) d
left join mytable t
on t.product = p.product
and t.yr = d.yr
and t.mn = d.mn
This puts nulls for rows with no sale - that's presumably a numeric column so you generally don't want to write a string like 'Not Sold' into it.
If there is a possibility of duplicate (product, yr, mn), you might want to use outer aggregation:
select
p.product,
sum(t.quantity_sold) quantity_sold,
d.yr,
d.mn
from (select distinct product from mytable) p
cross join (select distinct yr, mn from mytable) d
left join mytable t
on t.product = p.product
and t.yr = d.yr
and t.mn = d.mn
group by p.product, d.yr, d.mn
I'm trying to find the record revenue months by for each country. Below query provides me revenue by month for each country.
select d.calendar_year_month as 'Record_month',
c.country_name as 'country'
,sum(Net_qty*(unit_charge+unit_shipping_charge)) as 'Revenue'
from sensu_reporting.commercial_analysts.customer_science_transactions CST (nolock)
join Sensu.dbo.Country_D C (nolock) on cst.country_code = c.Country_Code
join sensu.dbo.Date_D d (nolock) on cst.Order_Date_Key = d.Date_Key
where cst.site_key in ('95')
and cst.order_date_key >= 20180101
group by d.calendar_year_month, c.country_name
I tried using:
select a.country,
a.record_month,
max(a.revenue) as 'Record_Revenue'
from(
select d.calendar_year_month as 'Record_month',
c.country_name as 'country'
,sum(Net_qty*(unit_charge+unit_shipping_charge)) as 'Revenue'
from sensu_reporting.commercial_analysts.customer_science_transactions CST (nolock)
join Sensu.dbo.Country_D C (nolock) on cst.country_code = c.Country_Code
join sensu.dbo.Date_D d (nolock) on cst.Order_Date_Key = d.Date_Key
where cst.site_key in ('95')
and cst.order_date_key >= 20180101
group by d.calendar_year_month, c.country_name)
a
group by country, record_month
However, this provides me the same data as the initial query. What am I doing wrong, and how do I amend my query such that it gives me only the month with the highest revenue per country?
Since I didn't know your table structure this is an simplified example with only one table (id, calendar_year_month, countrycode, revenue). I used a subquery to identify the max revenue.
select calendar_year_month, country, revenue
from reporting r
where revenue = (select max(revenue) from reporting r2 where r.country = r2.country )
group by calendar_year_month, country
And the result I got was like this
201802 NO 1500
201802 SE 3000
201803 DE 7000
201803 NO 1500
Notice there are two rows for NO.
I hope this is translatable to your table structure.
Is this what you want?
with r as (
select d.calendar_year_month as Record_month,
c.country_name as country,
sum(Net_qty*(unit_charge+unit_shipping_charge)) as Revenue
from sensu_reporting.commercial_analysts.customer_science_transactions CST join
Sensu.dbo.Country_D C
on cst.country_code = c.Country_Code join
sensu.dbo.Date_D d
on cst.Order_Date_Key = d.Date_Key
where cst.site_key in ('95') and cst.order_date_key >= 20180101
group by d.calendar_year_month, c.country_name
)
select r.*
from (select r.*,
row_number() over (partition by record_month order by revenue desc) as seqnum
from r
) r
where seqnum = 1;
I am using the Nortwind database with SQL Server 2014, I try to make a query to divide the results of the orders in two different years, The format that I want in my query is
category |anio one | anio two
where the years may vary , What I try so far is
SELECT ca.CategoryName , YEAR(o.OrderDate), SUM(ot.UnitPrice*ot.Quantity) as total
FROM Orders o
INNER JOIN [Order Details] ot ON O.OrderID = ot.OrderID
INNER JOIN Products pro ON ot.ProductID = pro.ProductID
INNER JOIN Categories ca ON pro.CategoryID = ca.CategoryID
GROUP BY ca.CategoryName,YEAR(o.OrderDate)
ORDER BY ca.CategoryName;
This gives me the totals of each category for a different year, 1996-1997-1998 in column YEAR(o.OrderDate)
I want to get for example
CategoryName | 1996 | 1997
Beverages |53879,20 | 110424,00
Condiments |19458,30 | 59679,00
....
Use "conditional aggregates".
SELECT
ca.CategoryName
, SUM(case when year(o.OrderDate) = 1996 then ot.UnitPrice * ot.Quantity end) AS total_1996
, SUM(case when year(o.OrderDate) = 1997 then ot.UnitPrice * ot.Quantity end) AS total_1997
FROM Orders o
INNER JOIN [Order Details] ot ON o.OrderID = ot.OrderID
INNER JOIN Products pro ON ot.ProductID = pro.ProductID
INNER JOIN Categories ca ON pro.CategoryID = ca.CategoryID
where o.OrderDate >= '19960101' and o.OrderDate < '19980101'
GROUP BY
ca.CategoryName
ORDER BY
ca.CategoryName
Basically that means use a case expression inside the aggregate function.
I case you are wondering why I have not used "between in the where clause: see
Bad habits to kick : mis-handling date / range queries
You can use PIVOT to get your desired Output
BEGIN TRAN
CREATE TABLE #Temp(CategoryName NVARCHAR(50),[Year]INT,TOTAL DECIMAL(15,2))
INSERT INTO #Temp
SELECT ca.CategoryName , YEAR(o.OrderDate), SUM(ot.UnitPrice*ot.Quantity) as total
FROM Orders o
INNER JOIN [Order Details] ot ON O.OrderID = ot.OrderID
INNER JOIN Products pro ON ot.ProductID = pro.ProductID
INNER JOIN Categories ca ON pro.CategoryID = ca.CategoryID
GROUP BY ca.CategoryName,YEAR(o.OrderDate)
ORDER BY ca.CategoryName;
SELECT * FROM #Temp
GO
select *
from
(
select CategoryName, [Year], TOTAL
from #Temp
) src
pivot
(
sum(TOTAL)
for YEAR in ([1996], [1997]
)) piv;
ROLLBACK TRAN
you can use pivot to get the desired output
CREATE TABLE #TEMP
(
Category VARCHAR(200),
YEAR1 NUMERIC,
Total MONEY
)
INSERT INTO #TEMP
SELECT 'beverages', 1996, 500
union
SELECT 'beverages', 1997, 750
union
SELECT 'Condiments', 1997, 1000
union
SELECT 'Condiments', 1996, 800
SELECT *
FROM
(
SELECT Category,YEAR1, Total FROM #TEMP
) AS SourceTable
PIVOT
(
AVG(Total) FOR YEAR1 IN ( [1996], [1997])
) AS PivotTable;
select SALESTABLE.CUSTACCOUNT,
SALESTABLE.salesname,
datename(month,SALESTABLE.SHIPPINGDATECONFIRMED)as Month,
sum(SALESLINE.LineAmount ) SaleAmount
from
SALESTABLE
inner join SALESLINE
on SALESTABLE.SALESID= SALESLINE.SALESID
WHERE SUBSTRING(SALESTABLE.CUSTACCOUNT, 1,2)='O-'
group by SALESTABLE.CUSTACCOUNT,
SALESTABLE.salesname,
datename(month,SALESTABLE.SHIPPINGDATECONFIRMED)
order by SALESTABLE.salesname,
datename(month,SALESTABLE.SHIPPINGDATECONFIRMED)
can i convert this query into pivot i want to show month name at the top of the table like Column Header and sum of LineAmount bellow these month columns
select *
from (select SALESTABLE.CUSTACCOUNT,
SALESTABLE.salesname,
datename(month,SALESTABLE.SHIPPINGDATECONFIRMED)as Month,
SALESLINE.LineAmount
from
SALESTABLE
inner join SALESLINE
on SALESTABLE.SALESID= SALESLINE.SALESID
WHERE SUBSTRING(SALESTABLE.CUSTACCOUNT, 1,2)='O-'
) t pivot (sum (LineAmount) for Month in (January,February,March,April,May,June,July,August,September,October,November,December)) p