Monthly sales as column - sql

SQL question, making monthly and yearly sales as column:
I have two tables:
t_items (item_num, item_name, itm_qnt)
t_items_dtl (item_num, invdate, itm_qnt_out, itm_qnt_in)
Columns are:
itm_qnt = current stock
invdate = invoice date
item_qnt_out = number of sold specific item in the invoice
item_qnt_in = number of returned specific item in the invoice
I want to get the following columns:
item_num | item_name | currnt_stock | QTY sold 2018 | QTY sold:Jan2018 | Feb 2018 | March 2018 .... Dec 2018
For now I used this query but it gives me only the total sales of each item:
SELECT
i.item_num AS ItemNum,
i.item_name AS ItemName,
sum(d.itm_qnt_out-d.itm_qnt_in) AS QTOUT,
i.itm_qnt AS Stock
FROM
dbo.t_items AS i
FULL OUTER JOIN
t_items_dtl AS d ON i.item_num = d.item_num
GROUP BY
i.item_num, i.item_name, i.itm_qnt;
How can I add monthly and yearly sales by column (not rows)?

Depending on the database you are using there may be more elegant ways to get year and month from a date but bottom-line, you probably want something like:
SELECT
i.item_num AS ItemNum,
i.item_name AS ItemName,
sum(d.itm_qnt_out-d.itm_qnt_in) AS QTOUT,
sum(CASE WHEN to_char(invdate,'mm') = '01' THEN d.itm_qnt_out-d.itm_qnt_in ELSE 0 END) AS QTOUTJan,
sum(CASE WHEN to_char(invdate,'mm') = '02' THEN d.itm_qnt_out-d.itm_qnt_in ELSE 0 END) AS QTOUTFeb,
sum(CASE WHEN to_char(invdate,'mm') = '03' THEN d.itm_qnt_out-d.itm_qnt_in ELSE 0 END) AS QTOUTMar,
/*Repeat for every month*/
i.itm_qnt AS Stock
FROM
dbo.t_items AS i
FULL OUTER JOIN
t_items_dtl AS d ON i.item_num = d.item_num
WHERE to_char(invdate, 'yyyy') = '2018'
GROUP BY
i.item_num, i.item_name, i.itm_qnt;
Compared to your code, I have defined a column for each month + added a WHERE to filter the entire thing to 2018.

Related

SQL How to group data into separate month columns

So I'm running this query to get the name of the customer, total amount ordered, and number of orders they've submitted. With this query, I get their entire history from March to July, what I want is the name, march amount total/# of orders, april amount total/# of orders, may amount total/# of orders, ..... etc.
SELECT customer_name,MONTH(created_on), SUM(amount), COUNT(order_id)
FROM customer_orders
WHERE created_on BETWEEN '2020-03-01' AND '2020-08-01'
GROUP BY customer_name, MONTH(created_on)
If you want the values in separate columns, then use conditional aggregation:
SELECT customer_name,
SUM(CASE WHEN MONTH(created_on) = 3 THEN amount END) as march_amount,
SUM(CASE WHEN MONTH(created_on) = 3 THEN 1 ELSE 0 END) as march_count,
SUM(CASE WHEN MONTH(created_on) = 4 THEN amount END) as april_amount,
SUM(CASE WHEN MONTH(created_on) = 4 THEN 1 ELSE 0 END) as april_count,
. . .
FROM customer_orders
WHERE created_on >= '2020-03-01' AND
created_on < '2020-08-01'
GROUP BY customer_name;
Notice that I changed the date filter so it does not include 2020-08-01.

sql completion of a result where it miss some results in the sequence

I have a table with sales information
like this: |product | sales | date|
Most of the time the date are consecutive from 201601 to 201652.
but some times there is a gap ex : no line for 201602 for productA
How can I make an SQL query that will return a result for this gap like this :
productA,4,201601
**productA,0,201602**
productA,5,201603
productA,8,201604
(...)
instead of :
productA,4,201601
productA,5,201603
productA,8,201604
(...)
Of course it will also be some product B,C,...
You do this by using cross join to get all the rows and then left join to pull in the values.
Assuming you have some data for each week:
select p.product, d.date, coalesce(s.sales, 0) as sales
from (select distinct product from sales) p cross join
(select distinct date from sales) d left join
sales s
on s.product = p.product and s.date = d.date;
If you have tables of products and dates, you can use those instead of the subqueries.
Starting from oracle 10g you can use partition outer join to produce desired result:
-- sample of data
with sales(product, sales, dt) as(
select 'product A', 4, 201601 from dual union all
select 'product A', 5, 201603 from dual union all
select 'product A', 8, 201604 from dual
),
-- here we generate months for the year 2016
mnth(dt) as(
select 201600 + level
from dual
connect by level <= 12
)
-- actual query
select s.product
, nvl(s.sales, 0) as sales
, m.dt as date1
from sales s
partition by(s.product)
right join mnth m
on (m.dt = s.dt)
order by s.product, m.dt
Result:
PRODUCT SALES DATE1
--------- ---------- ----------
product A 4 201601
product A 0 201602
product A 5 201603
product A 8 201604
product A 0 201605
product A 0 201606
product A 0 201607
product A 0 201608
product A 0 201609
product A 0 201610
product A 0 201611
product A 0 201612
12 rows selected
based on Gordon's response, I edited so date does not depend on Sales table. Here assumption is that tab will have atleast 52 row, if not please use appropriate data-dictionary table from oracle.
select p.product, d.date, coalesce(s.sales, 0) as sales
from (select distinct product from sales) p cross join
(select 2016 || rownum rn from tab where rownum<=52) d left join
sales s
on s.product = p.product and s.date = d.date;

Display 12 months of data from the past 5 years

I am currently creating a script that will pull 5 years of invoice data and will summarize the invoice amounts by month of that year for a specific customer. Example
Year jan feb mar
2011 800 900 700
2012 700 800 900, and so forth
I am having issues getting my output to be like this though. My current code
select MAX(cust) as customer,year(invoicedate) as y, month(invoicedate) as m, sum(amount) as summary
from #tquery
group by year(dinvoice), month(dinvoice)
having MAX(ccustno) ='WILLAMETTE'
order by y asc,m asc
select * from #tquery
gives me this. which i just need to find a way to reformat it.
customer year month amount
WILLAMETTE 2012 11 500
WILLAMETTE 2012 12 600
WILLAMETTE 2013 1 600
No need to go through a Pivot. It is only 12 columns. A conditional aggregation would be more efficient
Select Customer = cust
,Year = year(invoicedate)
,Jan = sum(case when month(invoicedate) = 1 then amount else 0 end)
,Feb = sum(case when month(invoicedate) = 2 then amount else 0 end)
...
,Dec = sum(case when month(invoicedate) =12 then amount else 0 end)
From #tquery
Group by ccustno,year(dinvoice)
Order By 1,2
You must using PIVOT to reformat rows to column
select customer
,y
,"1","2","3","4","5","6","7","8","9","10","11","12"
from (select cust as customer,year(invoicedate) as y, month(invoicedate) as m,amount
from #tquery
where ccustno ='WILLAMETTE'
)
t
pivot (sum (amount) for m in ("1","2","3","4","5","6","7","8","9","10","11","12")) p
order by y
;

How to calculate a growing or decreasing percentage between rows usign group by

Let's suposse that I have this table_1:
Year Item Qty_sold
2013 1 3
2013 2 2
2013 3 5
2014 1 2
2014 2 3
I'll perform something like this
select year , sum(Qty_sold) as Quantity
from table_1 inner join table_2 on .... inner join table_n
where Year = 2014
The final result depends mostly on the filter by year, but there are other tables involved.
But as a result I need something like this:
Year Quantity Diff_Percentage
2014 5 0.5
Because during the previous year (2013) the final quantity of items sold was 10.
Regards
You seem to want something like this:
select year, sum(Qty_sold) as Quantity,
lag(sum(qty_sold)) over (order by year) as prev_Quantity,
(1 - Quantity / lag(sum(qty_sold)) over (order by year)) as diff_percentage
from table
group by Year;
Of course, this returns the info for all years. If you really just want the year 2014 and 2013 then use conditional aggregation:
select year,
sum(case when year = 2014 then Qty_sold end) as Quantity_2014,
sum(case when year = 2013 then Qty_sold end) as Quantity_2013,
(1 - sum(case when year = 2014 then Qty_sold end)/
sum(case when year = 2013 then Qty_sold end)
) as diff_percentage
from table
where Year in (2013, 2014);
I'm sort of guessing on the formula for diff_percentage, but I think that's what you want.
As per your requirement, please try this
select t.year,qty, (1-qty/prev_qty)
from
(select year, sum(Qty_sold) as qty,
lag(sum(qty_sold)) over (order by year) as prev_qty
from tbl group by Year) t where t.year=in_year --in_year whichever year record you want.
Hope it works for you.

SQL Query - Group and SUM of Values

I have the following database structure:
ID | Payment (Decimal) | PaymentDate (DateTime) | PaymentStatus(int)
I am currently able to get a grouping of all of the payments over time by Year and Date and get the total across all Payment Status's using the following query;
Select
YEAR = YEAR(DueDate),
MONTH = MONTH(DueDate),
MMM = UPPER(left(DATENAME(MONTH,DueDate),3)),
Totals = sum(Payment)
from
PaymentSchedules
Where DueDate IS NOT NULL
Group by
YEAR(DueDate),
MONTH(DueDate),
DATENAME(Month,DueDate)
Order By
YEAR,
MONTH
This gives me the results so far so good.
What I would like to be able to do is have added totals for the splits in each section. So for example if each payment could be Paid (1) or Unpaid (2) or Overdue (3) I would like to not only get the number of paid / unpaid / overdue but I would also like to get the total value of unpaid items / paid items / Overdue items for each Year / Month combination.
You just need to add SUMs with CASE statements inside to only sum payments when the correct status is detected, like this:
Select YEAR = YEAR(DueDate),
MONTH = MONTH(DueDate),
MMM = UPPER(left(DATENAME(MONTH,DueDate),3)),
TotalPaid = sum(case when PaymentStatus = 1 then Payment else 0 end),
TotalUnpaid = sum(case when PaymentStatus = 2 then Payment else 0 end),
TotalOverdue = sum(case when PaymentStatus = 3 then Payment else 0 end),
Totals = sum(Payment)
from PaymentSchedules
Where DueDate IS NOT NULL
Group by YEAR(DueDate),
MONTH(DueDate),
DATENAME(Month,DueDate)
Order By YEAR,
MONTH
Since there are only 3 categories, I would suggest use CASE statement directly.
Select
YEAR = YEAR(DueDate),
MONTH = MONTH(DueDate),
MMM = UPPER(left(DATENAME(MONTH,DueDate),3)),
Paid_sum = sum(CASE When PaymentStatus = 1 THEN Payment ELSE 0 END),
Unpaid_sum = sum(CASE When PaymentStatus = 2 THEN Payment ELSE 0 END),
Overdue_sum = sum(CASE When PaymentStatus = 3 THEN Payment ELSE 0 END),
Totals = sum(Payment)
from
PaymentSchedules
Where DueDate IS NOT NULL
Group by
YEAR(DueDate),
MONTH(DueDate),
DATENAME(Month,DueDate)
Order By
YEAR,
MONTH