How can I pivot and then calculate data? - sql

Pretty new to SQL here. Thank you so much to anyone reading this.
I have a table
ProductID, Year, Sales
------------------------
Product1 2019 100
Product1 2018 50
With a lot of products, but the two years are always 2019 and 2018.
I need to show the 100 products that had the biggest % increase in sales.
I believe that this requires "pivoting" the data, so that you can calculate the 2019 (as one column) and 2018 (second column) difference in a third column called "% increase."
But I'm totally stuck--Ive never done anything this difficult in SQL before.
Help?

Another solution would be this, which would help you if there are more than one record per product - year:
SELECT
ProductId,
Sales_2018,
Sales_2019,
(Sales_2019 - Sales_2018) / Sales_2018 * 100 AS Percentage_increase
FROM (SELECT
ProductID,
SUM(CASE WHEN Year = 2018 THEN Sales END) AS Sales_2018,
SUM(CASE WHEN Year = 2019 THEN Sales END) AS Sales_2019
FROM TABLE
GROUP BY ProductID)
ORDER BY (Sales_2019 - Sales_2018) / Sales_2018 DESC

You can do this with self-join on almost any SQL engine.
Please find the sample implementation below.
You may need to fix some depending on the dialect that you use.
SELECT
a.ProductId,
(1.0 * b.Sales / a.Sales - 1.0) AS IncreaseRate
FROM
tbl AS a
INNER JOIN
tbl AS b
ON
a.ProductId = b.ProductId
AND a.year = 2018
AND b.year = 2019
ORDER BY
IncreaseRate DESC
LIMIT 100

Related

simple sql query highest sales

There are 2 tables - Products and Sales
Products
prod_id
prod_nm
Sales
prod_id
cust_id
sls_dt
sls_amt
Write a query selecting ALL the products. For each product show total of sales amounts in the past 30 days or 0 if not sold in 30 day withoug using subqueries.
Since different RDBMS have different date functions, you can filter by date using the following pseudo code - sls_dt > now() - 30.
Im new to sql and im trying it like this as i found this online.
Select prod_id, prod_nm from(
Select sls_amt
From Sales) as t
Where t.rank = 1
However, this isnt' working. Any help is appreciated
Try below:
select p.prod_id,
p.prod_nm,
sum(s.sls_amt)
from products p
left outer join Sales s on p.prod_id = s.prod_id
and s.sls_dt > now() - 30
group by p.prod_id,
p.prod_nm;

SQL Year over year growth percentage from data same query

How do I calculate the percentage difference from 2 different columns, calculated in that same query? Is it even possible?
This is what I have right now:
SELECT
Year(OrderDate) AS [Year],
Count(OrderID) AS TotalOrders,
Sum(Invoice.TotalPrice) AS TotalRevenue
FROM
Invoice
INNER JOIN Order
ON Invoice.InvoiceID = Order.InvoiceID
GROUP BY Year(OrderDate);
Which produces this table
Now I'd like to add one more column with the YoY growth, so even when 2016 comes around, the growth should be there..
EDIT:
I should clarify that I'd like to have for example next to
2015,5,246.28 -> 346,15942029% ((R2015-R2014) / 2014 * 100)
If you save your existing query as qryBase, you can use it as the data source for another query to get what you want:
SELECT
q1.Year,
q1.TotalOrders,
q1.TotalRevenue,
IIf
(
q0.TotalRevenue Is Null,
Null,
((q1.TotalRevenue - q0.TotalRevenue) / q0.TotalRevenue) * 100
) AS YoY_growth
FROM
qryBase AS q1
LEFT JOIN qryBase AS q0
ON q1.Year = (q0.Year + 1);
Access may complain it "can't represent the join expression q1.Year = (q0.Year + 1) in Design View", but you can still edit the query in SQL View and it will work.
What you are looking for is something like this?
Year Revenue Growth
2014 55
2015 246 4.47
2016 350 1.42
You could wrap the original query a twice to get the number from both years.
select orders.year, orders.orders, orders.revenue,
(select (orders.revenue/subOrders.revenue)
from
(
--originalQuery or table link
) subOrders
where subOrders.year = (orders.year-1)
) as lastYear
from
(
--originalQuery or table link
) orders
here's a cheap union'd table example.
select orders.year, orders.orders, orders.revenue,
(select (orders.revenue/subOrders.revenue)
from
(
select 2014 as year, 2 as orders, 55.20 as revenue
union select 2015 as year, 2 as orders, 246.28 as revenue
union select 2016 as year, 7 as orders, 350.47 as revenue
) subOrders
where subOrders.year = (orders.year-1)
) as lastYear
from
(
select 2014 as year, 2 as orders, 55.20 as revenue
union select 2015 as year, 2 as orders, 246.28 as revenue
union select 2016 as year, 7 as orders, 350.47 as revenue
) orders

Revenue year by year SQL Server query

I have the following query which provides me with the item and item details, values, rate and quantity across each location.
I am trying to get the yearly revenue based on the Start and End Date. Example, if the chosen date was 2013-2015. The final result will create 3 columns one for 2013 revenue, one for 2014 revenue and one for 2015 revenue.
I am a newbie and still not an expert in writing queries, but here is what I have currently:
SELECT
department,
item,
itemdesc,
qty1,
qty2,
rate_1,
rate_2,
SUM(mm.days*mm.rate*mm.qty)
FROM
items it
LEFT JOIN
(SELECT
i.days, i.rate, i.days, ii.todate, ii.itemid
FROM
invoiceofitems ii
JOIN
invoices i on i.id = ii.id
WHERE
ii.todate BETWEEN #StartDate and #EndDate) mm ON mm.itemid = it.itemid
GROUP BY
department,
item,
itemdesc,
qty1, qty2,
rate_1, rate_2
ORDER BY
item
However, this does not provide me with a year to year aggregation of invoice revenue that I require.
I know this is possible to achieve via iterating through this. But how would I accomplish this and where would I start on this?
Would I need to know the start and end date of each year and iterate through that and then add a counter to the year until year= EndDate?
I'm extremely confused. Help would be appreciated.
I hope that PIVOT and YEAR help you to solve this problem (some columns are omitted):
;WITH SRC(department,item, ... , rate_2, yr, calculation) AS
(SELECT it.department, it.item, ..., it.rate_2, YEAR(ii.todate) as yr,
(i.days * i.rate *i.qty) as calculation
FROM items it
LEFT JOIN invoiceofitems ii ON ii.itemid = it.itemid
JOIN invoices i ON i.id = ii.id)
SELECT department,item, ..., [2013],[2014],[2015]
FROM SRC
PIVOT
(SUM(calculation) FOR yr IN ([2013],[2014],[2015])) PVT
The YEAR function returns only 'year' part of your date and makes grouping easier. PIVOT just rotates grouped data from rows to columns.

sql query to calculate monthly growth percentage

I need to build a query with 4 columns (sql 2005).
Column1: Product
Column2: Units sold
Column3: Growth from previous month (in %)
Column4: Growth from same month last year (in %)
In my table the year and months have custom integer values. For example, the most current month is 146 - but also the table has a year (eg 2011) column and month (eg 7) column.
Is it possible to get this done in one query or do i need to start employing temp tables etc??
Appreciate any help.
thanks,
KS
KS,
To do this on the fly, you could use subqueries.
SELECT product, this_month.units_sold,
(this_month.sales-last_month.sales)*100/last_month.sales,
(this_month.sales-last_year.sales)*100/last_year.sales
FROM (SELECT product, SUM(units_sold) AS units_sold, SUM(sales) AS sales
FROM product WHERE month = 146 GROUP BY product) AS this_month,
(SELECT product, SUM(units_sold) AS units_sold, SUM(sales) AS sales
FROM product WHERE month = 145 GROUP BY product) AS last_month,
(SELECT product, SUM(units_sold) AS units_sold, SUM(sales) AS sales
FROM product WHERE month = 134 GROUP BY product) AS this_year
WHERE this_month.product = last_month.product
AND this_month.product = last_year.product
If there's a case where a product was sold in one month but not another month, you will have to do a left join and check for null values, especially if last_month.sales or last_year.sales is 0.
I hope I got them all:
SELECT
Current_Month.product_name, units_sold_current_month,
units_sold_last_month * 100 / units_sold_current_month prc_last_month,
units_sold_last_year * 100 / units_sold_current_month prc_last_year
FROM
(SELECT product_id, product_name, sum(units_sold) units_sold_current_month FROM MyTable WHERE YEAR = 2011 AND MONTH = 7) Current_Month
JOIN
(SELECT product_id, product_name, sum(units_sold) units_sold_last_month FROM MyTable WHERE YEAR = 2011 AND MONTH = 6) Last_Month
ON Current_Month.product_id = Last_Month.product_id
JOIN
(SELECT product_id, product_name, sum(units_sold) units_sold_last_year FROM MyTable WHERE YEAR = 2010 AND MONTH = 7) Last_Year
ON Current_Month.product_id = Last_Year.product_id
I am slightly guessing as the structure of the table provided is the result table, right? You will need to do self-join on month-to-previous-month basis:
SELECT <growth computation here>
FROM SALES s1 LEFT JOIN SALES s2 ON (s1.month = s2.month-1) -- last month join
LEFT JOIN SALES s3 ON (s1.month = s3.month - 12) -- lat year join
where <growth computation here> looks like
((s1.sales - s2.sales)/s2.sales * 100),
((s1.sales - s3.sales)/s3.sales * 100)
I use LEFT JOIN for months that have no previous months. Change your join conditions based on actual relations in month/year columns.

SQL query to identify seasonal sales items

I need a SQL query that will identify seasonal sales items.
My table has the following structure -
ProdId WeekEnd Sales
234 23/04/09 543.23
234 30/04/09 12.43
432 23/04/09 0.00
etc
I need a SQL query that will return all ProdId's that have 26 weeks consecutive 0 sales. I am running SQL server 2005. Many thanks!
Update: A colleague has suggested a solution using rank() - I'm looking at it now...
Here's my version:
DECLARE #NumWeeks int
SET #NumWeeks = 26
SELECT s1.ProdID, s1.WeekEnd, COUNT(*) AS ZeroCount
FROM Sales s1
INNER JOIN Sales s2
ON s2.ProdID = s1.ProdID
AND s2.WeekEnd >= s1.WeekEnd
AND s2.WeekEnd <= DATEADD(WEEK, #NumWeeks + 1, s1.WeekEnd)
WHERE s1.Sales > 0
GROUP BY s1.ProdID, s1.WeekEnd
HAVING COUNT(*) >= #NumWeeks
Now, this is making a critical assumption, namely that there are no duplicate entries (only 1 per product per week) and that new data is actually entered every week. With these assumptions taken into account, if we look at the 27 weeks after a non-zero sales week and find that there were 26 total weeks with zero sales, then we can deduce logically that they had to be 26 consecutive weeks.
Note that this will ignore products that had zero sales from the start; there has to be a non-zero week to anchor it. If you want to include products that had no sales since the beginning, then add the following line after `WHERE s1.Sales > 0':
OR s1.WeekEnd = (SELECT MIN(WeekEnd) FROM Sales WHERE ProdID = s1.ProdID)
This will slow the query down a lot but guarantees that the first week of "recorded" sales will always be taken into account.
SELECT DISTINCT
s1.ProdId
FROM (
SELECT
ProdId,
ROW_NUMBER() OVER (PARTITION BY ProdId ORDER BY WeekEnd) AS rownum,
WeekEnd
FROM Sales
WHERE Sales <> 0
) s1
INNER JOIN (
SELECT
ProdId,
ROW_NUMBER() OVER (PARTITION BY ProdId ORDER BY WeekEnd) AS rownum,
WeekEnd
FROM Sales
WHERE Sales <> 0
) s2
ON s1.ProdId = s2.ProdId
AND s1.rownum + 1 = s2.rownum
AND DateAdd(WEEK, 26, s1.WeekEnd) = s2.WeekEnd;