Add numbers from three different queries together - sql

I am getting average values for different past 3, 6 and 10 months.From following queries
select SUM(GrossAmount)/10 as Averageten
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -10, GETDATE())
select SUM(GrossAmount)/6 as Averagesix
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -6, GETDATE())
select SUM(GrossAmount)/3 as Averagethree
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -3, GETDATE())
I get three different values for example:
1200.22
2300.22
4500
I want to get the average of those three values like this
(1200.22 + 2300.22 + 4500) / 3
How can I add values from these separate queries.

Use union to merge three queries and then do average
select avg(Averageten)
from
(select SUM(GrossAmount)/10 as Averageten
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -10, GETDATE())
union
select SUM(GrossAmount)/6
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -6, GETDATE())
union
select SUM(GrossAmount)/3
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -3, GETDATE())
)a
OR you can use conditional aggregation to find the values as you query is from same table with different condition
select ((sum(case when CreatedDate >= DATEADD(MONTH, -10, GETDATE()) then GrossAmount end)/10)
+(sum(case when CreatedDate >= DATEADD(MONTH, -6, GETDATE()) then GrossAmount end)/6)
+(sum(case when CreatedDate >= DATEADD(MONTH, -3, GETDATE()) then GrossAmount end)/3))/3
from tablename

Use conditional aggregation.
SELECT
(
SUM(CASE WHEN CreatedDate >= DATEADD(MONTH, -10, GETDATE()) THEN GrossAmount END) / 10 +
SUM(CASE WHEN CreatedDate >= DATEADD(MONTH, -6, GETDATE()) THEN GrossAmount END) / 6 +
SUM(CASE WHEN CreatedDate >= DATEADD(MONTH, -3, GETDATE()) THEN GrossAmount END) / 3
) / 3 AS [10, 6, 3 Average]
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -10, GETDATE()) -- this covers all three cases

Related

SSRS Pull data from last year when January

Basically, when the report is run, I'd like to display YTD data; unless, it is January, then, I want to display all of last year.
I've been attempting to put this in my where statement, using case or iif. In both cases, I get the same error: Msg 102, Level 15, State 1... Incorrect syntax near 'between'.
SELECT
name,
owner,
duedate,
submitteddate
FROM Table
WHERE submitteddate IS NOT NULL AND
CASE WHEN MONTH(GETDATE()) = 1
THEN submitteddate between DATEADD(YEAR, DATEDIFF(YEAR, '19000101', GETDATE()) - 1 , '19000101') AND DATEADD(d, -1, DATEADD(YEAR, DATEDIFF(YEAR, '19000101', GETDATE()), '19000101'))))
ELSE submitteddate between DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AND GETDATE()))
end
It seems like related to usage of the bracelets. please try like below:
SELECT
name,
owner,
duedate,
submitteddate
FROM Table
WHERE submitteddate IS NOT NULL AND
CASE WHEN MONTH(GETDATE()) = 1
THEN submitteddate between DATEADD(YEAR, DATEDIFF(YEAR, '19000101', GETDATE()) - 1 , '19000101') AND DATEADD(d, -1, DATEADD(YEAR, DATEDIFF(YEAR, '19000101', GETDATE()), '19000101'))
ELSE submitteddate between DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AND GETDATE()
end
....WHERE YEAR(submitteddate) = YEAR(GETDATE())
- CASE WHEN MONTH(GETDATE()) = 1 THEN 1 ELSE 0 END
How about
WHERE
submitteddate >=
IIF(MONTH(GETDATE()) = 1, DATEADD(Year, -1, GETDATE()), '1900-01-01')
AND submitteddate <= GETDATE();
Or by using a variable
DECLARE #FromDate DATEIME = (SELECT IIF(MONTH(GETDATE()) = 1, DATEADD(Year, -1, GETDATE()), '1900-01-01'));
SELECT *
FROM Table
WHERE
submitteddate >=
#FromDate
AND submitteddate <= GETDATE();
Rather than using a CASE expression in the WHERE, which isn't SARGable, you would be far better off using variables:
DECLARE #StartDate DATE, #EndDate Date;
SET #StartDate = CASE DATEPART(MONTH,GETDATE()) WHEN 1 THEN DATEADD(YEAR, DATEDIFF(YEAR, 0,GETDATE())-1,0)
ELSE DATEADD(YEAR, DATEDIFF(YEAR,0,GETDATE()),0)
END;
SET #EndDate = DATEADD(YEAR,DATEDIFF(YEAR, 0,#StartDate)+1,0);
--SELECT #StartDate, #EndDate; --Uncomment to check the values, but would break SSRS, as it only reads the first returned dataset.
SELECT [name],
[owner],
duedate,
submitteddate
FROM [Table]
WHERE submitteddate >= #StartDate
AND submitteddate < #EndDate;
Note that there is no need to check if the value of submitteddate is NULL or not. NULL = {expression} will always result in "unknown", which isn't true and thus won't be returned in a data set. Thus if you don't want NULL values, then the IS NOT NULL clause is pointless in a WHERE like:
WHERE [Column] IS NOT NULL
AND [Column] = 1;
The above would return exactly the same rows as:
WHERE [Column] = 1;

SQL Server grouped rows return with default values if no row available for a date period

I'm trying to write a stored procedure which groups up rows based on their month and return a sum of all items if they exist and 0 if they don't.
For the date part of the query, what I am trying to get is today's date - extract the month and go back 5 months to gather any data if it exists.
At this stage, the query runs fine as is but I'm wondering if there's any way to optimise this as it looks like I'm running the same set of data over and over again and also it's hard coded to an extent.
The dataset I am trying to achieve is as follows:
Month TotalAmount TotalCount
-----------------------------------
2017-11 0 0
2017-12 200.00 2
2018-01 300.00 3
2018-02 0 0
2018-03 300.00 3
2018-04 100.00 1
Using the following query below, I was able to achieve what I want but as you can see, it's hard coding back the past 5 months so if I wanted to go back 12 months, I'd have to add in more code.
DECLARE #5MonthAgo date = CAST(DATEADD(MONTH, -5, GETDATE()) + 1 - DATEPART(DAY, DATEADD(MONTH, -5, GETDATE())) AS DATE)
DECLARE #4MonthAgo date = CAST(DATEADD(MONTH, -4, GETDATE()) + 1 - DATEPART(DAY, DATEADD(MONTH, -4, GETDATE())) AS DATE)
DECLARE #3MonthAgo date = CAST(DATEADD(MONTH, -3, GETDATE()) + 1 - DATEPART(DAY, DATEADD(MONTH, -3, GETDATE())) AS DATE)
DECLARE #2MonthAgo date = CAST(DATEADD(MONTH, -2, GETDATE()) + 1 - DATEPART(DAY, DATEADD(MONTH, -2, GETDATE())) AS DATE)
DECLARE #1MonthAgo date = CAST(DATEADD(MONTH, -1, GETDATE()) + 1 - DATEPART(DAY, DATEADD(MONTH, -1, GETDATE())) AS DATE)
DECLARE #CurrentMonth date = CAST(GETDATE() + 1 - DATEPART(DAY, GETDATE()) AS DATE)
-- Table to return grouped and sum data
DECLARE #StatsTable TABLE ([Month] DATE,
[Total Amount] DECIMAL(18,2),
[Total Count] INT
)
-- Temporary table to hold onto data batch - so table isn't used later on
DECLARE #TempGenTable TABLE ([Id] INT,
[Date] DATETIME,
[Lines] INT NULL,
[Amount] DECIMAL(18, 2) NULL
)
INSERT INTO #TempGenTable
SELECT
Id, Date, Lines, Amount
FROM
TallyTable
WHERE
Date >= #5MonthAgo
INSERT INTO #StatsTable
SELECT
#5MonthAgo,
COALESCE((SELECT SUM(Amount)
FROM #TempGenTable
WHERE Date >= #5MonthAgo AND Date < #4MonthAgo
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)), 0),
COALESCE((SELECT COUNT(Id)
FROM #TempGenTable
WHERE Date >= #5MonthAgo AND Date < #4MonthAgo
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)), 0)
UNION
SELECT
#4MonthAgo,
COALESCE((SELECT SUM(Amount)
FROM #TempGenTable
WHERE Date >= #4MonthAgo AND Date < #3MonthAgo
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)), 0),
COALESCE((SELECT COUNT(Id)
FROM #TempGenTable
WHERE Date >= #4MonthAgo AND Date < #3MonthAgo
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)), 0)
...
Is there an easier way to be able to get the above data with more flexibility in the number of months?
Is it better to just have the query pass in a month variable and it checks just the current month and have a loop within the controller to go back x number of months?
I would generate the data using a recursive CTE and then use left join:
with months as (
select datefromparts(year(getdate()), month(getdate()), 1) as month_start, 5 as n
union all
select dateadd(month, -1, month_start), n - 1
from months
where n > 0
)
select m.month_start, count(s.id), sum(s.amount)
from months m left join
#StatsTable s
on m.month_start = s.month
group by m.month_start
order by m.month_start;
You haven't provided sample data, so I'm not sure what s.month looks like. You might want the join condition to be:
on s.month >= m.month_start and s.month < dateadd(month, 1, m.month_start)
Below is a set-based method to generate the needed monthly periods:
--sample data
CREATE TABLE dbo.TallyTable (
Id int
, Date datetime
, Lines int
, Amount decimal(18, 2)
);
INSERT INTO dbo.TallyTable
VALUES
(1, '2017-12-05', 1, 50.00)
,(2, '2017-12-06', 1, 150.00)
,(3, '2018-01-10', 1, 100.00)
,(4, '2018-01-11', 1, 100.00)
,(5, '2018-01-12', 1, 100.00)
,(6, '2018-03-15', 1, 225.00)
,(7, '2018-03-15', 1, 25.00)
,(8, '2018-03-15', 1, 50.00)
,(9, '2018-04-20', 1, 100.00);
GO
DECLARE #Months int = 5; --number of historical months
WITH
t10 AS (SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t(n))
,t100 AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) - 1 AS num FROM t10 AS a CROSS JOIN t10 AS b)
, periods AS (SELECT
CONVERT(varchar(7), DATEADD(month, DATEDIFF(month, '', GETDATE()) - num, ''),121) AS Month
, DATEADD(month, DATEDIFF(month, '', CAST(GETDATE() AS date)) - num, '') AS PeriodStart
, DATEADD(month, DATEDIFF(month, '', CAST(GETDATE() AS date)) - num + 1, '') AS NextPeriodStart
FROM t100
WHERE num <= #Months
)
SELECT periods.Month, COALESCE(SUM(Amount), 0) AS TotalAmount, COALESCE(COUNT(ID), 0) AS TotalCount
FROM periods
LEFT JOIN dbo.TallyTable ON
TallyTable.Date >= PeriodStart
AND TallyTable.Date < NextPeriodStart
GROUP BY periods.Month
ORDER BY periods.Month;

How to extract data from 1st day of the month till today's date -1

I am trying to extract all the data that has the datetime from 1st day of the month till yesterday, for example:
01/06/2017 - 22/06/2017
I have used this code:
Select *
from testDb.dbo.Company1
WHERE MONTH(CreatedDate) = MONTH(dateadd(dd, -1, GetDate())) AND
YEAR(CreatedDate) = YEAR(dateadd(dd, -1, GetDate()))
EDIT
My column for CreatedDate, its data type is DateTime. Not sure if there is any difference tho.
But this prints out all the data from 01/06/2017 - 23/06/2017. What code should I write such that it will print all data till (today's date-1)? Thanks for the help and have a great day!
Instead of comparing the month and year components separately, try bounding your result set using a range of two complete data points, one being the start of the month, and the other being yesterday.
SELECT *
FROM testDb.dbo.Company1
WHERE
CreatedDate BETWEEN DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0) AND
DATEADD(day, -1, CAST(GETDATE() AS date))
Demo
Try this query --
SELECT *
FROM testDb.dbo.Company1
WHERE DATEPART(Month, CreatedDate) = Datepart(Month, GETDATE())
AND DATEPART(Day, CreatedDate) <= DATEPART(Day, Getdate())
Edit:
SELECT *
FROM testDb.dbo.Company1
WHERE DATEPART(Month, CreatedDate) = Datepart(Month, GETDATE())
AND DATEPART(Day, CreatedDate) < DATEPART(Day, Getdate())
Edit 2:
SELECT CONVERT(VARCHAR(30),CreatedDate,120) As [CreatedDate]
FROM testDb.dbo.Company1
WHERE DATEPART(Month, CreatedDate) = Datepart(Month, GETDATE())
AND DATEPART(Day, CreatedDate) < DATEPART(Day, Getdate())
This though wont work when today is the first day of the month
SELECT *
FROM your_table
WHERE createdDate BETWEEN
CAST('1 ' + DateName(month, GetDate()) + ' ' +Year(GetDate()) as datetime)
AND DATEADD(day, -1, GETDATE() )
I think this where clause does what you want:
where createdDate >= dateadd(month, 0, datediff(month, 0, getdate())) and
createdDate < cast(getdate() as date)

Sum of Dates between, T-SQL error

I'm trying to check if one of the join_date or date_of_change (date fields) are within the range and count them but I get an error:
sqlserver.jdbc.SQLServerException: The conversion from int to
TIMESTAMP is unsupported.
SUM(CASE WHEN (join_date BETWEEN DATEADD(day, -8, GETDATE()) AND DATEADD(day, -1, GETDATE())) OR (date_of_change BETWEEN DATEADD(day, -8, GETDATE()) AND DATEADD(day, -1, GETDATE())) THEN 1 ELSE 0 END) AS Total
Could someone explain to me what I'm doing wrong.
Original Code:
SELECT DISTINCT mtype, CASE WHEN (join_date BETWEEN DATEADD(day, -8,
GETDATE()) AND DATEADD(day, -1, GETDATE())) OR (date_of_change BETWEEN
DATEADD(day, -8, GETDATE()) AND DATEADD(day, -1, GETDATE())) THEN 1 ELSE 0
END AS Total FROM T0 GROUP BY mype, join_date,date_of_change
As #Alex K has said there could be another statement in the batch causing the problem as there doesn't seem to be any TimeStamp involved in this query.
Answering your last comment about the GROUP BY, you can simplify the query the following way:
SELECT
mtype, COUNT(1) as Total
FROM
T0
WHERE
(join_date BETWEEN DATEADD(day, -8, GETDATE()) AND DATEADD(day, -1, GETDATE()))
OR (date_of_change BETWEEN DATEADD(day, -8, GETDATE()) AND DATEADD(day, -1, GETDATE()))
GROUP BY
mype
But I am afraid that if the error is in a different statement.
I wrote the query again and it worked, must be a typo somewhere

How to use SQL to do a group by with different dates?

Lets say I have a table with the following columns:
Qty, INTEGER
SaleDate, DATETIME
I would now like to see this result:
Sold in the last 7 days | Sold in last 14 days
-----------------------------------------------------
10 | 20
I can use a where clause to use between, however how would I get the qty sold for 7 and 14 days?
Filter in the WHERE clause to get days 0 to -14. Then aggregate on days 0 to -7 separately.
SELECT
...,
SUM(CASE WHEN SaleDate >= DATEADD(day, -7, GETDATE()) THEN 1 ELSE 0 END) AS 7days,
COUNT(*) AS 14days
FROM
MyTable
WHERE
SaleDate >= DATEADD(day, -14, GETDATE())
GROUP BY
...
Tested in MS T-SQL 2003
declare #whatever table(
qty int,
saledate datetime
)
insert into #whatever select 1, getdate()
insert into #whatever select 2, dateadd(dd, -1, getdate())
insert into #whatever select 2, dateadd(dd, -2, getdate())
insert into #whatever select 1, dateadd(dd, -3, getdate())
insert into #whatever select 1, dateadd(dd, -4, getdate())
insert into #whatever select 1, dateadd(dd, -5, getdate())
insert into #whatever select 1, dateadd(dd, -6, getdate())
insert into #whatever select 1, dateadd(dd, -7, getdate())
insert into #whatever select 1, dateadd(dd, -8, getdate())
insert into #whatever select 1, dateadd(dd, -9, getdate())
insert into #whatever select 2, dateadd(dd, -10, getdate())
insert into #whatever select 2, dateadd(dd, -11, getdate())
insert into #whatever select 1, dateadd(dd, -15, getdate())
insert into #whatever select 2, dateadd(dd, -16, getdate())
select
qty,
sum(
case
when datediff(dd, saledate, getdate()) between 0 and 7 then 1
else 0
end
) as [Sold in last 7 days],
sum(
case
when datediff(dd, saledate, getdate()) between 0 and 14 then 1
else 0
end
) as [Sold in last 14 days]
from
#whatever
group by
qty
;
select sum(Qty), datediff(w, getdate(), SaleDate) as Period
from table
group by datediff(ww, getdate(), SaleDate)