Return 6 previous Month select last month - sql-server

SELECT DISTINCT itemcode,
itemdescription,
unitofmeasure,
Sum([current]) AS [Ending Balance]
WHERE transactiondate >= Dateadd(month, Datediff(month, 0,
Dateadd(m, -6, '2019-01-31'
)), 0)

Your code is missing FROM and GROUP BY clause and the Date Diff (Six Mont considering End Date = '2019-01-31') can be calculated as shown in the below script-
SELECT
itemcode,
itemdescription,
unitofmeasure,
Sum([current]) AS [Ending Balance]
FROM <your_table> -- FROM is missing. Please add appropriate table name
WHERE transactiondate Between
DATEADD(month, -6, '2019-01-31')
AND '2019-01-31'
GROUP BY itemcode,itemdescription,unitofmeasure
-- GROUP BY is required as you applied Aggregation on column [current]
If you wants only records from the 6th Previous month, WHERE condition will be as below-
WHERE YEAR(transactiondate) = YEAR(DATEADD(month, -6, '2019-01-31'))
AND MONTH(transactiondate) = MONTH(DATEADD(month, -6, '2019-01-31'))
For getting results from last 6 month, WHERE will be as below-
WHERE transactiondate BETWEEN
CAST(LEFT(CAST(DATEADD(MM,-6,CAST('2019-01-31' AS DATE)) AS VARCHAR),7) + '-01' AS DATE)
AND
DATEADD(DD,-1,CAST(CAST(LEFT(CAST(CAST('2019-01-31' AS DATE) AS VARCHAR),7) + '-01' AS DATE) AS DATE))
-- This is basically: transactiondate BETWEEN '2018-07-01' AND '2018-12-31'

Related

How to get data of current date using sum in SQL?

I'm working on a SQL query trying to fetch sum data for the current day/date. Can anyone have a look at my query, and find me a working solution?
SELECT SUM(amount)
FROM tbl_expense_record
WHERE dateonly = CAST(GETDATE() AS Date)
But I get data when mentioning a specific date in where condition like
SELECT SUM(amount) AS total
FROM tbl_expense_record
WHERE dateonly = '2020-06-12'
I want the a code to auto pick current date. Also I would like to fetch sum of ranged dates like a whole week, and a month!
select datename(month, '2020-06-12'), datename(month, getdate());
--1week
SELECT SUM(amount) AS total
FROM tbl_expense_record
WHERE dateonly >= dateadd(week, -1, cast(getdate() as date))
and dateonly <= cast(getdate() as date)
--1month
SELECT SUM(amount) AS total
FROM tbl_expense_record
WHERE dateonly >= dateadd(month, -1, cast(getdate() as date))
and dateonly <= cast(getdate() as date)
--build muscle memory (it is always safe to check for < date+1 instead of <= date)
--1month
SELECT SUM(amount) AS total
FROM tbl_expense_record
WHERE dateonly >= dateadd(month, -1, cast(getdate() as date))
and dateonly < dateadd(day, 1, cast(getdate() as date));
--6months
SELECT SUM(amount) AS total
FROM tbl_expense_record
WHERE dateonly >= dateadd(month, -6, cast(getdate() as date))
and dateonly < dateadd(day, 1, cast(getdate() as date));
if not exists
(
select *
FROM tbl_expense_record
WHERE dateonly >= dateadd(month, -1, cast(getdate() as date))
and dateonly < dateadd(day, 1, cast(getdate() as date))
)
begin
select 'no rows within the last month'
end
else
begin
select 'there are rows within the last month';
end;
Examples:
declare #tbl_expense_record table(dateonly date, amount decimal(9,2));
insert into #tbl_expense_record
values ('20200501', 10), ('20200612', 10), ('20200613', 11), ('20200614', 12),
('20200710', 5), ('20200720', 6), ('20200820', 20), ('20200825', 30),
('20201102', 1), ('20201110', 2), ('20201120', 3);
--aggregation per month, for all rows
select year(dateonly) as _year, month(dateonly) as _month, sum(amount) as sum_amount_per_month, count(*) as rows_per_month
from #tbl_expense_record
group by year(dateonly), month(dateonly);
--aggregation per iso-week
select year(dateonly) as _year, datepart(iso_week, dateonly) as _isoweek, sum(amount) as sum_amount_per_isoweek, count(*) as rows_per_isoweek
from #tbl_expense_record
group by year(dateonly), datepart(iso_week, dateonly);
--aggregation per month, for all rows with a dateonly that falls in the last month
--check the difference between aggregation per month earlier and this..
--filter rows first == where .... and then aggregate
--there are two rows with dateonly > 06 november (the row at 05 is filtered out by the where clause)
select year(dateonly) as _year, month(dateonly) as _month, sum(amount) as sum_amount_per_month, count(*) as rows_per_month
from #tbl_expense_record
where dateonly >= dateadd(month, -1, cast(getdate() as date))
and dateonly < dateadd(day, 1, cast(getdate() as date))
group by year(dateonly), month(dateonly);
--aggregate per week diff from today/getdate()
select
datediff(week, getdate(), dateonly) as week_diff_from_today,
dateadd(day,
--datepart(weekday..) is used...account for ##datefirst setting / set datefirst
1-(##datefirst+datepart(weekday, dateadd(week, datediff(week, getdate(), dateonly), cast(getdate() as date))))%7,
dateadd(week, datediff(week, getdate(), dateonly), cast(getdate() as date)))
as startofweek,
dateadd(day, 6, --add 6 days to startofweek
dateadd(day,
--datepart(weekday..) is used...account for ##datefirst setting / set datefirst
1-(##datefirst+datepart(weekday, dateadd(week, datediff(week, getdate(), dateonly), cast(getdate() as date))))%7,
dateadd(week, datediff(week, getdate(), dateonly), cast(getdate() as date)))
) as endofweek,
sum(amount) as sum_amount, count(*) as rows_within_week
from #tbl_expense_record
group by datediff(week, getdate(), dateonly);

Generate counts of records for each day in a week

I use SQL Server 2014 for my project. I have the following code to produce the number of registrations of each day:
SELECT
DATEADD(DAY, DATEDIFF(DAY, 0, createTime), 0) AS createdOn,
COUNT(*) AS Count
FROM
Registration
GROUP BY
DATEADD(DAY, DATEDIFF(DAY, 0, createTime), 0)
ORDER BY
createdOn
Now I would like to get the numbers for each day in a week (so there will be max 7 rows in output). How can I do it?
Here is the solution I have based on George's comment. Thank you, George!
SELECT
DATEPART(weekday, createTime) AS createdOn,
COUNT(*) AS Count
FROM
Registration
GROUP BY
DATEPART(weekday, createTime)
ORDER BY
createdOn
One way to return all days within a range returned with your data joined on matching days is to use a "calendar" table and LEFT JOIN your data by date.
DECLARE #StartDate DATETIME = '01/01/2015'
DECLARE #EndDate DATETIME = '12/01/2016'
//By Day In Year
;WITH Calender as
(
SELECT CalendarDate = #StartDate
UNION ALL
SELECT CalendarDate = DATEADD(DAY, 1, CalendarDate)
FROM Calender WHERE DATEADD (DAY, 1, CalendarDate) <= #EndDate
)
SELECT
C.CalendarDate,
COUNT(*) AS Count
FROM
Calender C
LEFT JOIN Regsitration R ON R.createdOn = C.CalendarDate
GROUP BY
C.CalendarDate
OPTION (MAXRECURSION 0)
//By Week In Year
;WITH Calender as
(
SELECT CalendarDate = #StartDate, WeekNumber=DATEPART(WEEK, #StartDate)
UNION ALL
SELECT CalendarDate = DATEADD(WEEK, 1, CalendarDate), WeekNumber=DATEPART(WEEK, #StartDate)
FROM Calender WHERE DATEADD (WEEK, 1, CalendarDate) <= #EndDate
)
SELECT
C.WeekNumber,
COUNT(*) AS Count
FROM
Calender C
LEFT JOIN Regsitration R ON DATEPART(WEEK,R.createdOn) = C.WeekNumber
GROUP BY
C.WeekNumber
OPTION (MAXRECURSION 0)

Is there a better way to group date rangers in T-SQL than CASE?

At the moment I'm having to run a lot of SQL queries where the results have to be grouped by date ranges. So far I've been doing it like this:
SELECT COUNT(*)
,CASE
WHEN Don_Date BETWEEN DATEADD(month, - 24, getdate())
AND GETDATE()
THEN 1
WHEN Don_Date BETWEEN DATEADD(month, -48, GETDATE())
AND DATEADD(month, - 24, getdate())
THEN 2
END AS DateRange
FROM #temp
GROUP BY CASE
WHEN Don_Date BETWEEN DATEADD(month, - 24, getdate())
AND GETDATE()
THEN 1
WHEN Don_Date BETWEEN DATEADD(month, -48, GETDATE())
AND DATEADD(month, - 24, getdate())
THEN 2
END
Which works, but it's kind of a pain to write.
I'm having to do this quite a lot, and for a lot of different potential date ranges. Is there a better - as in easier to write/less verbose/more malleable - way of doing this?
You could simplify it with a CTE:
WITH Ranges AS
(
SELECT t.*
,CASE
WHEN Don_Date BETWEEN DATEADD(month, - 24, getdate())
AND GETDATE()
THEN 1
WHEN Don_Date BETWEEN DATEADD(month, -48, GETDATE())
AND DATEADD(month, - 24, getdate())
THEN 2
END AS DateRange
FROM #temp t
)
SELECT Count = COUNT(*), DateRange
FROM Ranges
GROUP BY DateRange
With a join to a virtual values table.
select
rangedesc,COUNT(*)
from
yourtable
left join
(values
(DATEADD(month,-24,getdate()),getdate(), 1),
(DATEADD(month,-48,getdate()),DATEADD(month,-24,getdate()), 2)
) ranges(start,finish,rangedesc)
on yourtable.don_date between ranges.start and ranges.finish
group by rangedesc
If you prefer, you could move the date ranges to a CTE.
Of course, as with all date comparisons, be careful with the borders between two ranges. Compared to your original source code, if a date falls exactly 2 years ago, this method would put it in both ranges, rather than just one.
How about this?
;WITH myDates (DateRange, dtStart, dtEnd)
AS ( SELECT 1, DATEADD(MONTH, -24, GETDATE()), DATEADD(MONTH, 0, GETDATE())
UNION ALL SELECT 2, DATEADD(MONTH, -48, GETDATE()), DATEADD(MONTH, -24, GETDATE())
)
SELECT COUNT(*), DateRange
FROM #temp
JOIN myDates ON don_date BETWEEN dtStart AND dtEnd
GROUP BY DateRange

how to get data of current week only in SQL server?

I want records from table which stores the current date when a record is inserted with in current week only.
I have tried:
SELECT PId
,WorkDate
,Hours
,EmpId
FROM Acb
WHERE EmpId=#EmpId AND WorkDate BETWEEN DATEADD(DAY, -7, GETDATE()) AND GETDATE()
Do it like this:
SET DATEFIRST 1 -- Define beginning of week as Monday
SELECT [...]
AND WorkDate >= dateadd(day, 1-datepart(dw, getdate()), CONVERT(date,getdate()))
AND WorkDate < dateadd(day, 8-datepart(dw, getdate()), CONVERT(date,getdate()))
Explanation:
datepart(dw, getdate()) will return the number of the day in the current week, from 1 to 7, starting with whatever you specified using SET DATEFIRST.
dateadd(day, 1-datepart(dw, getdate()), getdate()) subtracts the necessary number of days to reach the beginning of the current week
CONVERT(date,getdate()) is used to remove the time portion of GETDATE(), because you want data beginning at midnight.
A better way would be
select datepart(ww, getdate()) as CurrentWeek
You can also use wk instead of ww.
Datepart Documentation
Its Working For Me.
Select * From Acb Where WorkDate BETWEEN DATEADD(DAY, -7, GETDATE()) AND DATEADD(DAY, 1, GETDATE())
You have to put this line After the AND Clause AND DATEADD(DAY, 1, GETDATE())
datepart(dw, getdate()) is the current day of the week, dateadd(day, 1-datepart(dw, getdate()), getdate()) should be the first day of the week, add 7 to it to get the last day of the week
You can use following query to extract current week:
select datepart(dw, getdate()) as CurrentWeek
SET DATEFIRST 1;
;With CTE
AS
(
SELECT
FORMAT(CreatedDate, 'MMMM-yyyy') as Months,
CASE
WHEN YEAR(DATEADD(DAY, 1-DATEPART(WEEKDAY, Min(CreatedDate)), Min(CreatedDate))) < YEAR(Min(CreatedDate))
THEN FORMAT(DATEADD(YEAR, DATEDIFF(YEAR, 0,DATEADD(YEAR, 0 ,GETDATE())), 0) ,'MMM dd') + ' - ' + FORMAT(DATEADD(dd, 7-(DATEPART(dw, Min(CreatedDate))), Min(CreatedDate)) ,'MMM dd')
ELSE
FORMAT(DATEADD(DAY, 1-DATEPART(WEEKDAY, Min(CreatedDate)), Min(CreatedDate)) ,'MMM dd') + ' - ' + FORMAT(DATEADD(dd, 7-(DATEPART(dw, Min(CreatedDate))), Min(CreatedDate)) ,'MMM dd')
END DateRange,
Sum(ISNULL(Total,0)) AS Total,
sum(cast(Duration as int)) as Duration
FROM TL_VriandOPI_Vendorbilling where VendorId=#userID and CompanyId=#CompanyID
Group By DATEPART(wk, CreatedDate) ,FORMAT(CreatedDate, 'MMMM-yyyy')
)
SELECT Months,DateRange,Total,Duration,
case when DateRange=(select FORMAT(DATEADD(DAY, 1-DATEPART(WEEKDAY, Min(getdate())), Min(getdate())) ,'MMM dd') + ' - ' +
FORMAT(DATEADD(dd, 7-(DATEPART(dw, Min(getdate()))), Min(getdate())) ,'MMM dd'))
then 1 else 0 end as Thisweek
FROM CTE order by Months desc
Using DATEDIFF works as well, however a bit hacky since it doesn't care about datefirst:
set datefirst 1; -- set monday as first day of week
declare #Now datetime = '2020-09-28 11:00';
select *
into #Temp
from
(select 1 as Nbr, '2020-09-22 10:00' as Created
union
select 2 as Nbr, '2020-09-25 10:00' as Created
union
select 2 as Nbr, '2020-09-28 10:00' as Created) t
select * from #Temp where DATEDIFF(ww, dateadd(dd, -##datefirst, Created), dateadd(dd, -##datefirst, #Now)) = 0 -- returns 1 result
select * from #Temp where DATEDIFF(ww, dateadd(dd, -##datefirst, Created), dateadd(dd, -##datefirst, #Now)) = 1 -- returns 2 results
drop table #Temp

Include missing months in Group By query

I think I have a tough one here... :(
I am trying to get an order count by month, even when zero. Here's the problem query:
SELECT datename(month, OrderDate) as Month, COUNT(OrderNumber) AS Orders
FROM OrderTable
WHERE OrderDate >= '2012-01-01' and OrderDate <= '2012-06-30'
GROUP BY year(OrderDate), month(OrderDate), datename(month, OrderDate)
What I'm looking to get is something like this:
Month Orders
----- ------
January 10
February 7
March 0
April 12
May 0
June 5
...but my query skips a row for March and May. I've tried COALESCE(COUNT(OrderNumber), 0) and ISNULL(COUNT(OrderNumber), 0) but I'm pretty sure the grouping is causing that not to work.
This solution doesn't require you to hard-code the list of months you might want, all you need to do is provide any start date and any end date, and it will calculate the month boundaries for you. It includes year in the output so that it will support more than 12 months and so that your start and end dates can cross a year boundary and still order correctly and show the correct month and year.
DECLARE #StartDate SMALLDATETIME, #EndDate SMALLDATETIME;
SELECT #StartDate = '20120101', #EndDate = '20120630';
;WITH d(d) AS
(
SELECT DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0))
FROM ( SELECT TOP (DATEDIFF(MONTH, #StartDate, #EndDate) + 1)
n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1
FROM sys.all_objects ORDER BY [object_id] ) AS n
)
SELECT
[Month] = DATENAME(MONTH, d.d),
[Year] = YEAR(d.d),
OrderCount = COUNT(o.OrderNumber)
FROM d LEFT OUTER JOIN dbo.OrderTable AS o
ON o.OrderDate >= d.d
AND o.OrderDate < DATEADD(MONTH, 1, d.d)
GROUP BY d.d
ORDER BY d.d;
Since your query Just Can't guess the months you want, you will need to have the Months that you want stored in somewhere, Join them with your table, and then group.
Something like:
;With Months (Month)
AS
(
select 'January' as Month
UNION
select 'February' as Month
UNION
select 'March' as Month
UNION
select 'April' as Month
UNION
select 'May' as Month
UNION
select 'June' as Month
UNION
select 'July' as Month
UNION
select 'August' as Month
UNION
select 'September' as Month
UNION
select 'October' as Month
UNION
select 'November' as Month
UNION
select 'December' as Month
)
--Also you could have them in a "Months" Table
Then Just JOIN this table with your table:
Select
SELECT datename(month, OrderDate) as Month, COUNT(OrderNumber)
FROM Months T1
LEFT JOIN OrderTable T2 on datename(month, T2.OrderDate) = T2.Month
WHERE (T2.OrderDate >= '2012-01-01' and T2.OrderDate <= '2012-06-30')
OR T2.OrderDate IS NULL --So will show you the months with no rows
GROUP BY year(T2.OrderDate), month(T2.OrderDate), datename(month, T2.OrderDate)
Hope it works!
Here is one using recursive CTE:
declare #StartDate datetime = '2015-04-01';
declare #EndDate datetime = '2015-06-01';
-- sample data
declare #orders table (OrderNumber int, OrderDate datetime);
insert into #orders
select 11, '2015-04-02'
union all
select 12, '2015-04-03'
union all
select 13, '2015-05-03'
;
-- recursive CTE
with dates
as (
select #StartDate as reportMonth
union all
select dateadd(m, 1, reportMonth)
from dates
where reportMonth < #EndDate
)
select
reportMonth,
Count = count(o.OrderNumber)
from dates
left outer join #orders as o
on o.OrderDate >= reportMonth
and o.OrderDate < dateadd(MONTH, 1, reportMonth)
group by
reportMonth
option (maxrecursion 0);
;

Resources