How to resolve SQL SUM not working correctly? - sql

I have an SQL data table called sales that records product, quantity sold, unit price, and the date of the sale. I would like to create a view with monthly sales for chairs from 2000-2010. That is, for every unique month and year pair I would like to sum up quantity * unit_price where the product = "CHAIR". My attempt is the following:
CREATE VIEW MONTHLY_SALES(product, monthly_sales, month, year) AS (
SELECT product, SUM(quantity * unit_price) AS monthly_sales,
TO_CHAR(sale_date, 'Month') AS month, EXTRACT(YEAR FROM sale_date) AS year
FROM sales
WHERE sale_date BETWEEN '2000-01-01' AND '2010-12-31' AND product = 'CHAIR'
GROUP BY quantity, unit_price, article, sale_date);
SELECT *
FROM MONTHLY_SALES;
I would expect to sum over the same month and year and get something like:
product | monthly_sales | month | year
Chair 100 January 2001
Chair 110 February 2001
Chair 120 March 2001
Chair 300 April 2001
But I'm seeing different monthly_sales for the same month-year pairs so I don't know why the SUM isn't working. Any assistance to fix this would be much appreciated.
===============================================================
Sample Data:
product | quantity | unit_price | sales_date
Chair 1 40 2001-01-01
Chair 3 40 2001-01-02
Chair 4 40 2001-02-01
Chair 1 40 2001-02-05
Expected Output:
product | monthly_sales | month | year
Chair 160 January 2001
Chair 200 February 2001

SELECT product, SUM(quantity * unit_price) AS monthly_sales,
EXTRACT(MONTH from sales_date) AS month, EXTRACT(YEAR FROM sales_date) AS year
FROM sales
WHERE sales_date BETWEEN '2000-01-01' AND '2010-12-31' AND product = 'CHAIR'
group by product, year, month
I've created a fiddle
Your group by is wrong - you're not grouping by product, month and year. What you're asking is "every time you see a change in any of quantity, price, article (whatever that is) and date, perform the sum". That will create lots of duplicates (if you have two sales in a given year/month combination, your group by says "create a new row because you've seen a change in sales date).

You are grouping by the sales date, instead of the month and year of the sale. You will get one record per sales_date instead of one record per month. This example will work in your case:
CREATE VIEW MONTHLY_SALES(product, monthly_sales, month, year) AS (
SELECT product, SUM(quantity * unit_price) AS monthly_sales,
TO_CHAR(sale_date, 'Month') AS month, EXTRACT(YEAR FROM sale_date) AS year
FROM sales
WHERE sale_date BETWEEN '2000-01-01' AND '2010-12-31' AND product = 'CHAIR'
GROUP BY article, TO_CHAR(sale_date, 'Month'), EXTRACT(YEAR FROM sale_date));
SELECT *
FROM MONTHLY_SALES

Related

Summing sales dollars for most recent month and 2nd most recent month

For each of the 12 months, I'm looking to create a field that sums the sales dollars at the account level for the most recent month and the 2nd most recent month based on the current date.
For example, given that today's date is 10/6/22, 'MostRecentNovember' would sum up sales from November 2021. '2ndMostRecentNovember' would sum up sales from November 2020. Once the current date moves into November 2022, this query would adjust to pull MostRecentNovember sales from 2022 and 2ndMostRecentNovember sales from 2021.
Conversely, given that today's date is 10/6/22 'MostRecentJune' would sum up sales from June 2022 and '2ndMostRecentJune' would sum up sales from June 2021.
Below is my attempt at this code, I think this gets partially there, but not sure it's exactly what I want
SELECT NovemberMostRecent_Value =
sum(case when datepart(year,tran_date) = datepart(year, getdate())
AND DATEPART(month, tran_date) = 11 then value else 0 end)
NovemberSecondMostRecent_Value =
sum(case when datepart(year,tran_date) = datepart(year, getdate())-1
AND DATEPART(month, tran_date) = 11 then value else 0 end)
Here's a snippet of the source data table
account_no
tran_date
value
123
11/22/21
500
123
11/1/21
500
123
11/20/20
1500
123
6/3/22
5000
123
6/4/21
2000
456
11/3/20
525
456
11/4/21
125
Per Request in Comments. A table of desired Results
account_no
NovemberMostRecent
November2ndMostRecent
June MostRecent
June2ndMostRecent
123
1000
1500
5000
2000
456
125
525
0
0
Why don't you just sum up the sales then group by month and year for the last two years? Wouldn't that solve the problem?
Or you can show a table that depicts what you are trying to achieve.
This should work fine.
Note: I only assume the account_no is the same for all the rows, if they are different, then you will need to pass it as a condition in the subquery.
WITH CTE AS
(SELECT (SELECT SUM(value) FROM tablename WHERE datepart(year, tran_date) = YEAR(getdate()) AND datepart(month, tran_date) = 11)
AS first_value,
(SELECT SUM(value) FROM tablename WHERE datepart(year, tran_date) = YEAR(getdate())-1 AND datepart(month, tran_date) = 11)
AS second_value,
(SELECT SUM(value) FROM tablename WHERE datepart(year, tran_date) = YEAR(getdate())-2 AND datepart(month, tran_date) = 11)
AS third_value)
SELECT IIF (first_value>0, first_value, second_value) AS NovemberMostRecent_Value,
IIF (first_value>0, second_value, third_value) AS NovemberSecondMostRecent_Value FROM CTE;

Regarding last year value from the date field

I have a table with the columns Sales_Date and Sales. I am looking for a solution to get Sales for the last year from the Sales_Date Column. Sales_Date column has values from the year 2015 onwards.
For example:
Sales_Date
Sales
1/1/2016
$25
1/8/2016
$57
1/1/2015
$125
1/8/2015
$21
I am looking for the below result set:
Sales_Date
Sales
LYear_Sales_Date
LYear_Sales
1/1/2016
$25
1/1/2015
$125
1/8/2016
$57
1/8/2015
$21
Filter all data to this year (WHERE YEAR(Sales.Sales_Date) = 2016).
LEFT JOIN to the same table, combining each date with the same date one year prior (Sales LEFT JOIN Sales AS Sales_LastYear ON Sales_LastYear.Sales_Date = DATEADD(year, -1, Sales.Sales_Date)).
SELECT the fields that you want (SELECT Sales.Sales_Date, Sales_LastYear.Sales_Date AS LYear_Sales_Date, ...).
Replace the LEFT JOIN with an INNER JOIN, if you want only those records that have a matching last-year record.
Seems like LAG would work here. Assuming you are always wanting the for the same (day and) month:
WITH CTE AS(
SELECT Sales_Date,
Sales,
LAG(Sales_Date) OVER (PARTITION BY DAY(Sales_Date), MONTH(Sales_Date) ORDER BY YEAR(Sales_Date)) AS LYear_Sales_Date,
LAG(Sales) OVER (PARTITION BY DAY(Sales_Date), MONTH(Sales_Date) ORDER BY YEAR(Sales_Date)) AS LYear_Sales
FROM dbo.YourTable)
SELECT Sales_Date,
Sales,
LYear_Sales_Date,
LYear_Sales
FROM CTE
WHERE Sales_Date >= '20160101'
AND Sales_Date < '20170101';

Sales amounts of the top n selling vendors by month in bigquery

i have a table in bigquery like this (260000 rows):
vendor date item_price
x 2021-07-08 23:41:10 451,5
y 2021-06-14 10:22:10 41,7
z 2020-01-03 13:41:12 74
s 2020-04-12 01:14:58 88
....
exactly what I want is to group this data by month and find the sum of the sales of only the top 20 vendors in that month. Expected output:
month sum_of_only_top20_vendor's_sales
2020-01 7857
2020-02 9685
2020-03 3574
2020-04 7421
.....
Consider below approach
select month, sum(sale) as sum_of_only_top20_vendor_sales
from (
select vendor,
format_datetime('%Y%m', date) month,
sum(item_price) as sale
from your_table
group by vendor, month
qualify row_number() over(partition by month order by sale desc) <= 20
)
group by month
Another solution that potentially can show much much better performance on really big data:
select month,
(select sum(sum) from t.top_20_vendors) as sum_of_only_top20_vendor_sales
from (
select
format_datetime('%Y%m', date) month,
approx_top_sum(vendor, item_price, 20) top_20_vendors
from your_table
group by month
) t
or with a little refactoring
select month, sum(sum) as sum_of_only_top20_vendor_sales
from (
select
format_datetime('%Y%m', date) month,
approx_top_sum(vendor, item_price, 20) top_20_vendors
from your_table
group by month
) t, t.top_20_vendors
group by month

SQL Query: Find highest revenue month/year for a customer

I'm looking to query the database to find highest revenue month for all the customers in the system. I have got the query working to pull customers monthly revenue from all the years for which the data is present. But I'm struggling to figure out how to get highest revenue month-year from this data.
The database is SQL Server 2008 R2.
The columns are: Customer name, Year, Month, and Revenue.
I even tried using Row_Number() and tried partitioning by customer name/year and ordering by revenue. But it didn't work. Maybe I'm making some mistake there.
Here's how I tried to build the base query.
Select Customer, Year(orderdatetime) as Year, Month(orderdatetime) as Month, SUM(Revenue)
From Orders
Group By Customer, Year(orderdatetime), Month(orderdatetime)
This is how I tried to use Row_Number()
WITH Max_Revenue AS
(
Select Customer, Year(orderdatetime) as Year, Month(orderdatetime) as Month, SUM(Revenue), RowNumber = ROW_NUMBER() OVER(PARTITION By Year Order By Revenue DESC)
From Orders
Group By Customer, Year(orderdatetime), Month(orderdatetime)
)
Select Max_Revenue.Customer, Max_Revenue.Year, Max_Revenue.Month, Max_Revenue.Revenue
From Max_Revenue
Where Max_Revenue.RowNumber = 1
Order By Max_Revenue.Customer asc
The data I get back is like:
Customer Month Year Revenue
ABC 2 2012 100
ABC 3 2013 150
ABC 5 2012 200
XYZ 4 2011 500
XYZ 6 2012 650
XYZ 7 2012 800
What I want as the output is
Customer Month Year Revenue
ABC 5 2012 200
XYZ 7 2012 800
So every customer's best month and respective year in terms of revenue.
SELECT Customer,
Year,
Revenue,
Month
FROM (
SELECT Customer,
Year,
ROW_NUMBER() OVER(PARTITION By Customer Order By Revenue DESC) as rank,
Revenue,
Month
FROM (
Select Customer,
Year(orderdatetime) as Year,
Month(orderdatetime) as Month,
SUM(Revenue) as Revenue
From Orders
Group By
Customer,
Year(orderdatetime),
Month(orderdatetime)
) BS
GROUP BY Customer,
Year,
Month) BS2
WHERE BS2.rank = 1
OR change = ROW_NUMBER() OVER(PARTITION By Year Order By Revenue DESC to
= ROW_NUMBER() OVER(PARTITION By Customer Order By Revenue DESC

Oracle SQL Query:Find out which year total sales amount is maximum

my working table, Table name: sales
Here Is MY TABLE, [sl_no is primary key] table structure:
CREATE TABLE SALES
( SL_NO NUMBER PRIMARY KEY, REGION VARCHAR2(10) NOT NULL,
MONTH VARCHAR2(20) NOT NULL, YEAR NUMBER NOT NULL,
SALES_AMOUNT NUMBER NOT NULL )
and here is table data:
SQL> select * from sales;
SL_NO REGION MONTH YEAR SALES_AMOUNT
---------- ---------- -------------------- ---------- ------------
1 east december 2011 750000
2 east august 2011 800000
3 west january 2012 640000
5 east march 2012 1200000
6 west february 2011 580000
4 west april 2011 555000
6 rows selected.
I have tried this query to view total sales amount of those[2011,2012] year;
SELECT year, SUM(sales_amount) FROM sales GROUP BY year;
YEAR SUM(SALES_AMOUNT)
---------- -----------------
2011 2685000
2012 1840000
MY GOAL:> I want to find out the year of maximum sales amount.
I tried this,and work perfectly...but when i want to display that year also, it gives an Error.
SQL> select max(sum(sales_amount)) from sales group by year;
MAX(SUM(SALES_AMOUNT))
----------------------
2685000
SQL> select year, max(sum(sales_amount)) from sales group by year;
select year, max(sum(sales_amount)) from sales group by year
*
ERROR at line 1:
ORA-00937: not a single-group group function
Extra addition: if multiple rows have same value means....when sales amount of both year[2011,2012] remain same, Then....
plZ help me to Solve this problem.
This should work.
with yr_agg as (
select year, sum(sales_amount) as total
from sales
group by year
)
select year, total as max_total
from yr_agg
where total = (select max(total)
from yr_agg);
I think the simplest way is to order the results and take the first row:
select year, sales_amount
from (SELECT year, SUM(sales_amount) as sales_amount
FROM sales
GROUP BY year
order by sum(sales_amount) desc
) t
where rownum = 1;
EDIT:
If you need to display all the matching rows (which isn't mentioned in the question), I would suggest using the dense_rank() analytic function:
select year, sales_amount
from (SELECT year, SUM(sales_amount) as sales_amount,
dense_rank(over order by SUM(sales_amount) desc) as seqnum
FROM sales
GROUP BY year
order by sum(sales_amount) desc
) t
where seqnum = 1;
Or, you might like the max() version instead:
select year, sales_amount
from (SELECT year, SUM(sales_amount) as sales_amount,
max(sum(sales_amount)) over () as maxsa
FROM sales
GROUP BY year
order by sum(sales_amount) desc
) t
where sales_amount = maxsa;
Following select should do what you need (untested, do not have Oracle at home):
select year, total
from (
select year, sum(sales_amount) total
from sales
group by year
)
where total = (select max(total_amount)
from (
select year, sum(sales_amount) total_amount
from sales
group by year
))
Take in account, though, that it might give you different years in each execution if two of them have exactly the same total amount. You might want to include some more conditions to avoid this.
Here is my Query where multiple row can select
SELECT year,MAX(total_sale) as max_total
FROM
(SELECT year,SUM(sales_amount) AS total_sale FROM sales GROUP BY year)
GROUP BY
year HAVING MAX(total_sale) =
(SELECT MAX(total_sale) FROM (SELECT SUM(sales_amount) AS total_sale FROM sales GROUP BY year));