Display 2 count results in Single Query - sql

I have an orders table and I want to display a report showing the Month, Total Orders and Total Orders rejected from the single table.
the table has dtcomplete, rtpID and supplierReject that i want to use, this nearly gets me there but there should only be 1 reject showing for January, I want the subquery to only check the grouped month
select datename(month, dtComplete) as Month, count(rtpID) as TotalOrders,
(select count(*) from RTPMaindetails where SupplierRejected = 1 and datename(month, dtComplete) = datename(month, RTPMaindetails.dtComplete) group by datepart(month,dtcomplete) ) as Rejects
from RTPMaindetails
where datepart(year,dtComplete) = 2017
group by datepart(month,dtcomplete),datename(month, dtComplete)
order by datepart(month,dtcomplete)
Shows:
Month TotalOrders Rejects
January 515 1
February 308 1
March 156 1
Should show
Month TotalOrders Rejects
January 515 1
February 308 0
March 156 0

This may depend on what DBMS you're using, but most should support something like this:
select datename(month, dtComplete) as Month
, count(rtpID) as TotalOrders,
, count(case when SupplierRejected = 1 then rtpID end) as Rejects
from RTPMaindetails
where datepart(year,dtComplete) = 2017
group by datepart(month,dtcomplete),datename(month, dtComplete)
order by datepart(month,dtcomplete)

you could do with a single query
select
datename(month, dtComplete) as Month
, count(rtpID) as TotalOrders
, sum( case when SupplierRejected = 1 then 1 else 0 ) as Rejects
from RTPMaindetails
where datepart(year,dtComplete) = 2017
group by datepart(month,dtcomplete)
order by datepart(month,dtcomplete)

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;

BigQuery - Year over Year Comparison with Month to Date

I am having trouble accurately doing a year over year comparison by month but at any point during the month. For example for August 2022 vs 2021, I want to compare August 1 to today, rather than full month of August 2021.
My data has a date field.
I want the final result to basically be:
Product_ID, Year, Month, PY_Sales, CY_Sales
I have daily totals. Some products do have not sales on certain days though. Here's an example:
product_id
sale_date
units
1
2021-01-01
5
2
2021-01-02
4
...
...
...
1
2021-06-05
2
2
2021-08-01
1
2
2021-08-31
6
2
2022-01-06
1
2
2022-08-15
9
The final result for August should be:
product_id
Year
Month
PY_Sales
CY_Sales
2
2022
8
1
9
Right now my code will show 7 for August for product_id = 2 because 6 sales happened on August 31st but that day hasn't happened yet in 2022.
This is the code I have, but it doesn't do MTD. Right now, PY_Sales for August 2022 is showing the entire August of 2021, but I want it to show the MTD of August 2021. I used this code because some products do not have sales on certain months.
WITH cte AS
(
SELECT
PRODUCT_ID,
EXTRACT(YEAR FROM SALE_DATE) AS Year,
EXTRACT(MONTH FROM SALE_DATE) AS Month,
CONCAT(EXTRACT(YEAR FROM SALE_DATE), '-',EXTRACT(MONTH FROM SALE_DATE)) AS Year_Month,
SUM(Units) AS Units
FROM data
WHERE Product_ID = 1
AND DATE(SALE_DATE) >= '2019-01-01'
GROUP BY 1, 2, 3
),
diff AS
(
SELECT
COALESCE(c.PRODUCT_ID, p.PRODUCT_ID) AS Product_ID,
COALESCE(c.Year, p.Year + 1) AS Year,
COALESCE(c.Month, p.Month) AS Month,
IFNULL(c.Units, 0) AS Current_Units,
IFNULL(p.Units, 0) AS Previous_Units,
NULLIF(((IFNULL(c.Units, 0) - IFNULL(p.Units,0)) / p.Units),0) * 100 AS Percent_Change
FROM CTE c
FULL OUTER JOIN CTE p ON c.PRODUCT_ID = p.PRODUCT_ID AND c.Year = p.Year + 1 AND c.Month = p.Month
WHERE c.Year <= EXTRACT(YEAR FROM CURRENT_DATE())
ORDER BY 2, c.Year, c.Month
)
SELECT *
FROM diff
--This is to avoid dividing by 0
WHERE diff.Previous_Units > 0
--AND Percent_Change <= -.5
I'm being a little repetitive but I hope this is clear! Thank you so much!
In the cte table you summarize the sold units by month and year.
Your question can be solved by adding here a column units_last_year. This contains the units, which are sold up to the day one year ago. Today is the 27th of August 2022, therefore the units on the 31th of August 2021 will be set to zero.
SUM(Units) AS Units,
SUM(IF(SALE_DATE< date_sub(current_Date(),interval 1 year), Units, 0 )) as units_last_year
Please use the safe_divide command, if there is any chance of diving by zero
Here is the full query with example data.
You given an example of fixed dates, which are compared to the current date. Therefore, the query would not show the desired effect after 30th of August 2022.
The product_id three is made up values related to the current date, thus the following query yields results after August 2022.
with data as (
select *,date(sale_date_) as sale_date
from (
Select 1 product_id, "2021-01-01" sale_date_, 5 units
union all select 2,"2021-01-02", 4
union all select 1,"2021-06-05", 2
union all select 2,"2021-08-01", 1
union all select 2,"2021-08-31", 6
union all select 2,"2022-01-06", 1
union all select 2,"2022-08-15", 9
union all select 3, current_date(), 10
union all select 3, date_sub(current_date(),interval 1 year), 9
union all select 3, date_sub( date_trunc(current_date(),month),interval 1 year), 1
)
),
cte AS
(
SELECT
PRODUCT_ID,
EXTRACT(YEAR FROM SALE_DATE) AS Year,
EXTRACT(MONTH FROM SALE_DATE) AS Month,
CONCAT(EXTRACT(YEAR FROM SALE_DATE), '-',EXTRACT(MONTH FROM SALE_DATE)) AS Year_Month,
SUM(Units) AS Units,
sum(if(SALE_DATE< date_sub(current_Date(),interval 1 year), units, 0 )) as units_last_year
FROM data
WHERE # Product_ID = 1 AND
DATE(SALE_DATE) >= '2019-01-01'
GROUP BY 1, 2, 3, 4
),
diff AS
(
SELECT
COALESCE(c.PRODUCT_ID, p.PRODUCT_ID) AS Product_ID,
COALESCE(c.Year, p.Year + 1) AS Year,
COALESCE(c.Month, p.Month) AS Month,
IFNULL(c.Units, 0) AS Current_Units,
IFNULL(p.Units, 0) AS Previous_Units,
IFNULL(p.Units_last_Year, 0) AS Previous_Units_ok,
NULLIF(((IFNULL(c.Units, 0) - IFNULL(p.Units,0)) / p.Units),0) * 100 AS Percent_Change,
NULLIF(safe_divide((IFNULL(c.Units, 0) - IFNULL(p.Units_last_Year,0)) , p.Units_last_Year),0) * 100 AS Percent_Change_ok,
FROM CTE c
FULL OUTER JOIN CTE p ON c.PRODUCT_ID = p.PRODUCT_ID AND c.Year = p.Year + 1 AND c.Month = p.Month
WHERE c.Year <= EXTRACT(YEAR FROM CURRENT_DATE())
ORDER BY 2, c.Year, c.Month
)
SELECT *
FROM diff

What to use in place of union in above query i wrote or more optimize query then my given query without union and union all

I am counting the birthdays , sales , order in all 12 months from customers table in SQL server like these
In Customers table birth_date ,sale_date, order_date are columns of the table
select 1 as ranking,'Birthdays' as Type,[MONTH],TOTAL
from ( select DATENAME(month, birth_date) AS [MONTH],count(*) TOTAL
from customers
group by DATENAME(month, birth_date)
)x
union
select 2 as ranking,'sales' as Type,[MONTH],TOTAL
from ( select DATENAME(month, sale_date) AS [MONTH],count(*) TOTAL
from customers
group by DATENAME(month, sale_date)
)x
union
select 3 as ranking,'Orders' as Type,[MONTH],TOTAL
from ( select DATENAME(month, order_date) AS [MONTH],count(*) TOTAL
from customers
group by DATENAME(month, order_date)
)x
And the output is like these(just dummy data)
ranking
Type
MONTH
TOTAL
1
Birthdays
January
12
1
Birthdays
April
6
1
Birthdays
May
10
2
Sales
Febrary
8
2
Sales
April
14
2
Sales
May
10
3
Orders
June
4
3
Orders
July
3
3
Orders
October
6
3
Orders
December
17
I want to find count of these all these three types without using UNION and UNION ALL, means I want these data by single query statement (or more optimize version of these query)
Another approach is to create a CTE with all available ranking values ​​and use CROSS APPLY for it, as shown below.
WITH ranks(ranking) AS (
SELECT * FROM (VALUES (1), (2), (3)) v(r)
)
SELECT
r.ranking,
CASE WHEN r.ranking = 1 THEN 'Birthdays'
WHEN r.ranking = 2 THEN 'Sales'
WHEN r.ranking = 3 THEN 'Orders'
END AS Type,
DATENAME(month, CASE WHEN r.ranking = 1 THEN c.birth_date
WHEN r.ranking = 2 THEN c.sale_date
WHEN r.ranking = 3 THEN c.order_date
END) AS MONTH,
COUNT(*) AS TOTAL
FROM customers c
CROSS APPLY ranks r
GROUP BY r.ranking,
DATENAME(month, CASE WHEN r.ranking = 1 THEN c.birth_date
WHEN r.ranking = 2 THEN c.sale_date
WHEN r.ranking = 3 THEN c.order_date
END)
ORDER BY r.ranking, MONTH

Query two unbalanced tables

Sum across two tables returns unwanted Sum from one table multiplied by the number of rows in the other
I have 1 table with Actual results recorded by date and the other tables contains planned results recorded by month.
Table 1(Actual)
Date Location Amount
01/01/2019 Loc1 1000
01/02/2019 Loc1 700
01/01/2019 Loc2 7500
01/02/2019 Loc2 1000
02/01/2019 Loc1 500
Table 2(Plan)
Year Month Location Amount
2019 1 Loc1 1500
2019 1 Loc2 8000
2019 2 Loc1 800
I have tried various differed Joins using YEAR(Table1.date) and Month(table1.date) and grouping by
Month(Table1.Date) but I keep running into the same problem where the PlanAmount is multiplied by however many rows in the Actual table...
in the example of loc1 for Month 1 below I get
Year Month Location PlanAmount ActualAmount
2019 1 Loc1 3000 1700
I would like to return the below
Year Month Location PlanAmount ActualAmount
2019 1 Loc1 1500 1700
2019 1 Loc2 8000 8500
2019 2 Loc1 800 500
Thanks in advance for any help
D
You can do this with a full join or union all/group by:
select yyyy, mm, location,
sum(actual_amount) as actual_amount,
sum(plan_amount) as plan_amount
from ((select year(date) as yyyy, month(date) as mm, location,
amount as actual_amount, 0 as plan_amount
from actual
group by year(date) as yyyy, month(date) as mm, location
) union all
(select year, month, location,
0 as actual_amount, amount as plan_amount
from actual
group by year, month, location
)
) ap
group by yyyy, mm, location;
This ensures that you have rows, even when there are no matches in the other table.
To get the required results you need to group the first table on year of date, month of date and location and need to select the columns year, month, location and sum of amount from group after that you need to join that resultant r
SELECT
plans.year,
plans.month,
plans.location,
plans.plan_amount,
grouped_results.actual_amount
FROM plans
INNER JOIN (
SELECT
datepart(year, date) AS year,
datepart(month, date) AS month,
location,
SUM(amount) AS actual_amount
FROM actuals
GROUP BY datepart(year, date), datepart(month, date), location
) as grouped_results
ON
grouped_results.year = plans.year AND
grouped_results.month = plans.month AND
grouped_results.location = plans.location
I think the problem is that you are using sum(PlanTable.Amount) when grouping. Try using max(PlanTable.Amount) instead.
select
p.Year,
p.Month,
p.Location,
sum(a.Amount) as actual_amount,
max(p.Amount) as plan_amount
from
[Plan] p left join Actual a
on year(a.date) = p.year
and month(a.date) = p.Month
and a.Location = p.Location
group by
p.year,
p.month,
p.Location
SQL Fiddle
get year and month from date and use them in join , most dbms has year and month functions you can use according to your DBMS
select year(t1.date) yr,month(t1.date) as monthofyr ,t1.Location,
sum(t1.amount) as actual_amoun,
sum(t2.amount) as planamount
from table1 t1 left join table2 t2 on
month(t1.date)= t2.Month and t1.Location=t2.Location
and year(t1.date)=t2.year
group by year(t1.date) ,month(t1.date),Location

SQL Sum by week from daily table

I have a table with sales for products.
The sales are per day. like
product date sales
1 '2013-11-01' 100
1 '2013-11-02' 423
1 '2013-11-03' 700
1 '2013-11-04' 233
2 '2013-11-01' 623
2 '2013-11-02' 451
2 '2013-11-03' 9000
I want to get a query which will show me the week over week sum of sales
So something like:
product week ending sales
1 '2013-11-01' 10000
1 '2013-11-08' 15000
2 '2013-11-01' 4900
2 '2013-11-08' 30000
I'm not sure how I get this weekly groups when summing up.
I'm using teradata
If you are using Teradata 14 you can leverage the DayNumber_Of_Week() function in the database TD_SYSFNLIB:
SELECT s.Product
, s.Date + (7-DayNumber_Of_Week(s.date)) AS WeekEndingDate /* Saturday */
, SUM(s.Sales) AS Sales
FROM sales AS S
GROUP BY 1,2;
This should work in Teradata 13.10 as well.
Using Sys_Calendar:
SELECT s.Product
, s.DATE + (7-c.Day_Of_Week) AS WeekEndingDate /* Saturday */
, SUM(s.Sales) AS Sales
FROM sales AS S
INNER JOIN
Sys_Calendar.Calendar c
ON S.date = c.calendar_date
GROUP BY 1,2;
I know very little about TERADATA, but I believe you can leverage the sys_calendar.calendar table, something like:
SELECT s.Product, c.week_of_year, SUM(s.sales) AS Sales
FROM sales AS s
JOIN sys_calendar.calendar as C
ON s.date = c.date
You'd need the Year in there as well, so as to not group up week 1 of 2013 with week 1 of 2012.