Removing Null results from AVG - sql

I've been doing some work regarding AVG. My previous solution didn't work. However, after some revision and help it's now returning the correct results. The results do however, keep returning NULL Values for agents as they don't have results in the CASE WHEN date range.
I've tried adding IS NOT NULL into CASE WHEN argument but it tells me the expression does not exist.
SELECT Employee,
AVG(CASE WHEN SaleDate >= '2019-01-01' AND SaleDate < '2019-04-01' THEN NewScheme END),
AVG(CASE WHEN SaleDate >= '2019-01-04' AND SaleDate < '2019-04-07' THEN NewScheme END),
FROM Salereport
WHERE Business Area = 'Sales'
GROUP BY Employee;
When adding is not null i'm told the expression doesn't exist.

You can simply add a WHERE clause to remove employees that do not have sales in either range. It could still show NULL in one of the average columns though:
SELECT Employee,
AVG(CASE WHEN SaleDate >= '2019-01-01' AND SaleDate < '2019-04-01' THEN NewScheme END),
AVG(CASE WHEN SaleDate >= '2019-01-04' AND SaleDate < '2019-04-07' THEN NewScheme END)
FROM Salereport
WHERE Business Area = 'Sales'
AND SaleDate >= '2019-01-01' AND SaleDate < '2019-04-07'
-- if the ranges do not overlap then list them separately and combine with "OR"
GROUP BY Employee;

Build your query like this. Put ELSE 0 End and ISNULL() to avoid nulls your your AVG
SELECT Employee,
AVG(ISNULL(CASE WHEN SaleDate >= '2019-01-01' AND SaleDate < '2019-04-01'
THEN NewScheme ELSE 0 End, 0)
END),
AVG(ISNULL((CASE WHEN SaleDate >= '2019-01-04' AND SaleDate < '2019-04-07'
THEN NewScheme ELSE 0 End, 0)
END),
FROM Salereport
WHERE Business Area = 'Sales'
GROUP BY Employee;
OR
SELECT Employee,
AVG(CASE WHEN SaleDate >= '2019-01-01' AND SaleDate < '2019-04-01'
THEN ISNULL(NewScheme, 0) ELSE 0 End
END),
AVG((CASE WHEN SaleDate >= '2019-01-04' AND SaleDate < '2019-04-07'
THEN ISNULL(NewScheme, 0) ELSE 0 End
END),
FROM Salereport
WHERE Business Area = 'Sales'
GROUP BY Employee;

Related

AVG duplication SQL

I'm currently having issues creating two columns with AVG for different date ranges.
I've tried the below code to try and resolve this.
WITH Tbl AS(
SELECT FORMAT(SaleDate,'MM')+'.'+FORMAT(SaleDate,'yyyy') AS SALE_MY, Employee, NewScheme
FROM Salereport
WHERE Business Area='Sales'
)
SELECT
AgentName,
(SELECT AVG(NewScheme) FROM Tbl WHERE SALE_MY='01.2019' OR SALE_MY='02.2019' OR SALE_MY='03.2019'),
(SELECT AVG(NewScheme) FROM Tbl WHERE SALE_MY='04.2019' OR SALE_MY='05.2019' OR SALE_MY='06.2019')
FROM Tbl
GROUP BY Employee
Result is just the same AVG for everyone.
Use conditional aggregation:
SELECT Employee,
AVG(CASE WHEN SaleDate >= '2019-01-01' AND SaleDate < '2019-04-01'
THEN NewScheme
END),
AVG(CASE WHEN SaleDate >= '2019-01-04' AND SaleDate < '2019-04-07'
THEN NewScheme
END),
FROM Salereport
WHERE Business Area = 'Sales'
GROUP BY Employee;
When working with dates, you should be using date operations. The only time you normally need to convert to a string is to format dates in the result set.
Incidentally, your version is taking the average across all employees. No subquery is needed, but if you were to use one, you would want a correlated subquery.
Try this:
WITH Tbl AS(
SELECT FORMAT(SaleDate,'MM')+'.'+FORMAT(SaleDate,'yyyy') AS SALE_MY, Employee, NewScheme
FROM Salereport
WHERE Business Area='Sales'
)
SELECT Employee,
AVG(CASE WHEN SALE_MY IN ('01.2019', '02.2019', '03.2019') THEN NewScheme ELSE NULL END) AS Q1_Avg,
AVG(CASE WHEN SALE_MY IN ('04.2019', '05.2019', '06.2019') THEN NewScheme ELSE NULL END) AS Q2_Avg
FROM Tbl
GROUP BY Employee

Using DB2 column alias within same select

I have a working query but I'm trying to use the column aliases in order to create more calculations in my select and it says the column can't be found (i.e. it can't use the alias).
For instance, the working query:
select employee,
sum(case when date_field between '2018-01-01' and '2018-01-31' and category = 'CategoryOne' then salesprice else 0 end) as priorDate,
sum(case when date_field between '2018-01-01' and '2018-01-31' then salesprice else 0 end) as priorTotal,
cast(Round((DEC(sum(case when date_field between '2018-01-01' and '2018-01-31' and category = 'CategoryOne' then salesprice else 0 end),12,2)/sum(case when date_field between '2018-01-01' and '2018-01-31' then salesprice else 0 end)) * 100,2) as decimal(12,2)) as priorPercent,
sum(case when date_field between '2019-01-01' and '2019-01-31' and category = 'CategoryOne' then salesprice else 0 end) as currentDate,
sum(case when date_field between '2019-01-01' and '2019-01-31' then salesprice else 0 end) as currentSales,
cast(Round((DEC(sum(case when date_field between '2019-01-01' and '2019-01-31' and category = 'CategoryOne' then salesprice else 0 end),12,2)/sum(case when date_field between '2019-01-01' and '2019-01-31' then salesprice else 0 end)) * 100,2) as decimal(12,2)) as currentPercent
from table
group by employee;
But for my two percentages (the two rows that start with cast) I've tried using just priorDate / priorTotal but it won't work and so I have to repeat the 2 whole calculations as a percentage.
I want to also obtain a difference in percentages which would be much easier to declare by using the aliases, and maybe more performant?
You can write this using a CTE/subquery:
with t as (
select employee,
sum(case when date_field between '2018-01-01' and '2018-01-31' and category = 'CategoryOne' then salesprice else 0 end) as priorDate,
sum(case when date_field between '2018-01-01' and '2018-01-31' then salesprice else 0 end) as priorTotal,
sum(case when date_field between '2019-01-01' and '2019-01-31' and category = 'CategoryOne' then salesprice else 0 end) as currentDate,
sum(case when date_field between '2019-01-01' and '2019-01-31' then salesprice else 0 end) as currentSales,
from table
group by employee
)
select t.*,
round(t.priorDate * 100.0 / nullif(t.priorTotal, 0), 2) as priorPercent,
round(t.priorTotal * 100.0 / nullif(t.currentTotal, 0), 2) as currentPercent
from t;

Total Count of each

I have a problem with my SQL Server query.
My query must display the total number of each category. Not the total amount of all categories.
SELECT [CATEGORY],
(SELECT COUNT(*)
FROM [Group_New_DB].[dbo].[INCIDENTSM1]
WHERE ([OPEN_TIME] >= #StartDate and [OPEN_TIME] < #EndDate + 1) ) AS OpenedCount,
(SELECT COUNT(*)
FROM [Group_New_DB].[dbo].[INCIDENTSM1]
WHERE ([CLOSE_TIME] >= #StartDate and [CLOSE_TIME] < #EndDate + 1)) AS ClosedCount
FROM [Group_New_DB].[dbo].[INCIDENTSM1]
GROUP BY CATEGORY
ORDER BY CATEGORY
The report consists of a table with 3 columns: Category, Registered, Closed.
1 column is the category name.
2 column is how many categories have been registered.
3 column -> how many columns were closed.
But result
The result that turned out as a result does not look right.
I don't quite understand what is the difference between total number vs total amount as the question doesn't provide any context.
Although, if you are trying to get OpenedCount and ClosedCount as you have named the columns, I suggest you try below:
SELECT
CATEGORY,
SUM(CASE WHEN (OPEN_TIME >= #start_date AND OPEN_TIME < #end_date+1)
THEN 1
ELSE 0
END) AS OPENED_COUNT,
SUM(CASE WHEN (CLOSED_TIME >= #start_date AND CLOSED_TIME < #end_date+1)
THEN 1
ELSE 0
END) AS CLOSED_COUNT
FROM
[Group_New_DB].[dbo].[INCIDENTSM1]
GROUP BY
CATEGORY
ORDER BY
CATEGORY
IMO, This is also a better way as it doesn't include multiple sub-queries.
Correction: changed COUNT to SUM as suggested by TriV - Thanks!
Try this instead -
SELECT [CATEGORY],
COUNT(CASE WHEN [OPEN_TIME] >= #StartDate and [OPEN_TIME] < #EndDate + 1 THEN 1 ELSE NULL END) AS OpenedCount,
COUNT(CASE WHEN [CLOSE_TIME] >= #StartDate and [CLOSE_TIME] < #EndDate + 1 THEN 1 ELSE NULL END) AS ClosedCount
FROM [Group_New_DB].[dbo].[INCIDENTSM1] GROUP BY
CATEGORY ORDER BY CATEGORY

SQL: Create Multiple Selects Based One Date

I've been searching for help on this but I can't seem to find the solution. What I have is:
Table called Details_Orders.
Columns: CustomerName, InvoiceDate, SaleAmount and SaleCost.
What I want to do is select a date ('1-1-2015') and display the Customer Name, the Date ('1-1-2015'), the sum of SaleAmount for that Date, and the Sum of the SaleCost. And here's the part I'm having problems with, I want the next columns to display the previous months SaleAmount and SaleCost, then the previous YEARS SaleAmount and SaleCost.
I'm having trouble figuring out how to code the Previous Time Periods Select statements. Any help on this would be greatly appreciated.
Select
CustomerName,
InvoiceDate,
Sum(SaleAmount),
Sum(SaleCost),
*PREVIOUS MONTH Sum(SalesAmount) DATEADD(MONTH,-1,'1-1'2015'),
PREVIOUS MONTH Sum(SalesCost) DATEADD(MONTH,-1,'1-1'2015'),
PREVIOUS YEAR Sum(SalesAmount) DATEADD(YEAR,-1,'1-1'2015'),
PREVIOUS YEAR Sum(SalesCost) DATEADD(YEAR,-1,'1-1'2015')*
From Details_Orders
WHERE InvoiceDate='1-1-2015'
Basic
You want to use conditional aggregation, and also need a group by. It is a bit unclear what the exact definitions of previous month and year are. Here is one interpretation:
Select CustomerName,
Sum(case when InvoiceDate = thedate then SaleAmount else 0 end),
Sum(case when InvoiceDate = thedate then SaleCost else 0 end),
Sum(case when year(InvoiceDate)*12 + month(InvoiceDate) =
year(thedate)*12 + month(thedate) - 1
then SaleAmount else 0
end),
Sum(case when year(InvoiceDate)*12 + month(InvoiceDate) =
year(thedate)*12 + month(thedate) - 1
then SaleCost else 0
end),
Sum(case when InvoiceDate < thedate and
InvoiceDate >= dateadd(year, -1, thedate
then SaleAmount else 0
end),
Sum(case when InvoiceDate < thedate and
InvoiceDate >= dateadd(year, -1, thedate
then SaleCost else 0
end)
From (select cast('2015-01-01' as date) as thedate
) params cross join
Details_Orders o
group by CustomerName;

Revenue for two months date wise

I am trying to get data for last 2 month ...but the query does not give perfect result....
SELECT DAY(table_A.PaymentDate) as date1 ,
(case when MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP) - 1
then CAST(SUM(table_A.Total_Amount) AS INT)
else 0
end) AS last_month_CNT,
(case when MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP)
then CAST(SUM(table_A.Total_Amount) As INT)
else 0
end) as This_month_CNT
FROM Tbl_Pan_Paymentdetails table_A
FULL OUTER JOIN Tbl_Pan_Paymentdetails table_B
ON table_A.PaymentDate=table_B.PaymentDate
WHERE YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP)
AND
table_A.PaymentDate >= DATEADD(MONTH, -1, GETDATE())
GROUP BY
DAY(table_A.PaymentDate) ,MONTH(table_A.PaymentDate)
order by
DAY(table_A.PaymentDate);
Move the entire case expression inside the sum function and don't include the month in the group by. Also, the full outer join seems unnecessary so I removed it.
This should be what you are looking for:
SELECT
DAY(PaymentDate) as date1 ,
SUM(CASE WHEN MONTH(PaymentDate) = MONTH(CURRENT_TIMESTAMP)-1 THEN CAST(Total_Amount AS INT) ELSE 0 END) AS last_month_CNT,
SUM(CASE WHEN MONTH(PaymentDate) = MONTH(CURRENT_TIMESTAMP) THEN CAST(Total_Amount AS INT) ELSE 0 END) AS This_month_CNT
FROM Tbl_Pan_Paymentdetails
WHERE YEAR(PaymentDate) = YEAR(CURRENT_TIMESTAMP)
AND PaymentDate >= DATEADD(MONTH, -1, GETDATE())
GROUP BY DAY(PaymentDate)
ORDER BY DAY(PaymentDate);