is it possible to Sum values grouped by month? - sql

I have an SQL Server table structured as follows :
Table name : calendar.
Columns :
Calendar Date (smalldatetime)
Working Day (bit)
Calendar date has all dates, structured in the format yyyy-mm-dd.
Working day means that I have work if it is a 1, and if it is a weekend or a holiday it is marked as a 0.
What I want to retrieve :
Month No Working Days Year
------------------------------------
January 22 2011
February 20 2011
March 22 2011
...
December 10 2011
January 15 2012
All of the information is there, but I am just not sure how to write a query like this, but I assume it would be structured something similar to this with some fancy datetime functions thrown in. Does
SELECT Sum(Working Day)
GROUP BY (Not a clue)

Presumably you are interested in finding the working days in each month in each year and report which month the number of days is for. This will give you that:
SELECT YEAR([Calendar Date]) As [YEAR],
Month([Calendar Date]) As [Month],
SUM([Working Day] As [Working Days]
FROM [Calendar]
GROUP BY YEAR([Calendar Date]),
Month([Calendar Date])

Your query should look something like this:
SELECT Sum(Working Day)
WHERE Working Day = 1
GROUP BY MONTH(calenderDate)
This will group by month as you asked.
For more datetime functions your could check out this link

Something like this should work:
SELECT DATENAME(month, [Calendar Date]) 'Month',
COUNT(1) 'No Working Days',
YEAR([Calendar Date]) 'Year'
FROM YourTable
WHERE [Working Day] = 1
GROUP BY DATENAME(month, [Calendar Date]), YEAR([Calendar Date])
Depending your data and your desired results, if a month doesn't have any working days, this query won't return any results for that month. Instead, you could use something like this with CASE removing the WHERE criteria:
SELECT DATENAME(month, [Calendar Date]) 'Month',
COUNT(CASE WHEN [Working Day] = 1 THEN 1 END) 'No Working Days',
YEAR([Calendar Date]) 'Year'
FROM YourTable
GROUP BY DATENAME(month, [Calendar Date]), YEAR([Calendar Date])
You may not need the case statement at all -- depends on whether your table allows NULL for your bit field. If it doesn't allow NULLs, you can just use SUM([Working Day]) as it will sum 0s and 1s.
SQL Fiddle Demos

Try this one… it’s pretty much the same as most answers above with the addition of order by
SELECT YEAR(calendar_date) As [Year],
MONTH(calendar_date) As [Month],
SUM(working_day) As Working_Days
FROM [calendar]
GROUP BY YEAR(calendar_date) MONTH(calendar_date])
ORDER BY [Year], [Month]

Related

Fiscal Year from Current Date

I'm using SSMS/SSRS2012 working on report to capture all hours worked in the current fiscal year, which for this purpose is Oct 1-Sep 30.
I'm looking for a case statement that says the following:
if the current month < 10 (october) then #FYStart = last year
if the current month >= 10 then #FYStart = current year
When I query SELECT GETDATE() here is the format: 2020-06-16 15:24:57.637
I have tried the following, but it only half works.
SELECT CASE WHEN DATEPART(MONTH,(CAST(getdate() AS INT)))>09
THEN YEAR(CAST(getdate() AS INT))
ELSE DATEADD(YEAR,-1,(CAST(getdate() AS INT)))
END
The result from this gives me 2019-06-17 00:00:00.000 which is a step in the right direction, but if I change the month to a month that has already passed,
SELECT CASE WHEN DATEPART(MONTH,(CAST(getdate() AS INT)))>03
THEN YEAR(CAST(getdate() AS INT))
ELSE DATEADD(YEAR,-1,(CAST(getdate() AS INT)))
END
I get this result: 1905-07-14 00:00:00.000
Something is obviously going wrong here but I'm not sure what exactly. I'm thinking it's something with the data types but I'm not sure what to check/where to start.
So from what I gather, you are trying to isolate the year (as an integer) from today's date and store it in #FYStart. If today's date is before October, you want to assign it to last year, and if it's October or later, assign it to this year, correct?
If so, try this:
DECLARE #FYStart int
SET #FYStart = (
SELECT CASE WHEN DATEPART(MONTH, GETDATE()) < 10
THEN DATEPART(YEAR, DATEADD(YEAR, -1, GETDATE())) -- last year
ELSE DATEPART(YEAR, GETDATE()) -- this year
END
)
Unless I'm overlooking something, is it not just something as simple as...
SELECT CASE WHEN MONTH(getdate()) <10
THEN YEAR(getdate()) -1
ELSE YEAR(getdate())
END

last date of Financial year (I.e 2017-03-31)

Hi please let me know how to extract the last day of Financial year in sql server.my financial year start from 2016-04-01 to 2017-03-31
Closest you can use is End Of Month for that you need to provide one date to that month as below:
select eomonth('2017-03-01')
To get the last day of the financial year for any date, you need to find the last of march if before march, or the last of march next year if after march:
declare #yourdate datetime = getdate();
select case when month(#yourdate) < 4 then CONVERT(datetime,cast(YEAR(#yourdate) as char(4)) + '-03-31' ,120)
else CONVERT(datetime,cast(YEAR(#yourdate) + 1 as char(4)) + '-03-31' ,120)
end as financial_year_end
Edit:
If you want last date derived based on from_date, then use something like this
Rextester Demo
select
case when datepart(mm,from_date) <=3 then
cast(concat(year(from_date),'-03-31') as datetime)
else
dateadd(year,1,cast(concat(year(from_date),'-03-31') as datetime))
end as last_date_fin
from
(select '2017-04-30' as from_date union all
select '2017-01-13') t;
This way from_date between Jan - Mar will give same year's 31st march. Else it will give next year's 31st March.
Previous answer:
http://rextester.com/AXVM26769
If you want to get last day of march for same year as passed, then use
select cast(concat(given_year,'-03-31') as datetime)
from
(select '2017' as given_year) t
If you want to pass 2016 and then get 2017-03-31 then use. You can change the year in derived table and change the output based on that.
select dateadd(year,1,cast(concat(given_year,'-03-31') as datetime))
from
(select '2016' as given_year) t;
This Code will work to find the last date of Financial Year.
For Previous Year case matches and 'THEN' part will Execute and for current year 'ELSE'
part will execute.
select CASE WHEN (MONTH(GETDATE())) <= 3
THEN convert(varchar(4), YEAR(GETDATE())-1) + '-' + '03-31'
ELSE convert(varchar(4),YEAR(GETDATE()))+ '-' + '03-31'
end
> LastDayOfYearFY] =
> eomonth( dateadd(month, 5,
> dateadd(year, datepart(year, (dateadd(month, 6, [date])) ) -1900, 0)))
Idea extension taken from return-first-day-of-financial-year
You can select all the dates order them descendant and take the first one.
SELECT date
FROM table
ORDER BY date desc
LIMIT 1;

DATEADD Calculation

How the calculation happen for MONTH datepart in DATEADD()
Add Month
SELECT '2012-01-29' AS [Date], CAST(DATEADD(MONTH, 1, '2012-01-31') AS DATE) AS NextDate
UNION
SELECT '2012-01-31' AS [Date], CAST(DATEADD(MONTH, 1, '2012-01-31') AS DATE) AS NextDate
UNION
SELECT '2013-01-31' AS [Date], CAST(DATEADD(MONTH, 1, '2013-01-31') AS DATE) AS NextDate
Result
Subtract Month
SELECT '2012-02-29' AS [Date], CAST(DATEADD(MONTH, -1, '2012-02-29') AS DATE) AS PrevDate
UNION
SELECT '2012-03-01' AS [Date], CAST(DATEADD(MONTH, -1, '2012-03-01') AS DATE) AS PrevDate
Result
When I add a Month for the dates 29,30,31 of Jan'2012, I get the same result as February 29. For subtract, for the date 29 Feb'2012, it shows 29 Jan'2012. There is no way to get the dates 30 & 31 of Jan'2012.
I want to know some brief explanation.
The behaviour is explicitly documented in the documentation for DATEADD:
DATEADD (datepart , number , date )
...
If datepart is month and the date month has more days than the return month and the date day does not exist in the return month, the last day of the return month is returned. For example, September has 30 days; therefore, the two following statements return 2006-09-30 00:00:00.000:
SELECT DATEADD(month, 1, '2006-08-30');
SELECT DATEADD(month, 1, '2006-08-31');
As to why it has this behaviour, it all comes down to the fact that variable length months mean that you have to apply some form of tradeoff when performing date maths, and no one "correct" answer exists. Do you think of 31st January as being "the last day of January" or "30 days after the 1st day of January". Both of those are correct ways of thinking about the 31st. But if you change January to February, you now obtain two different dates - 28th or 29th of February for "the last day of February" or 2nd or 3rd of March for "30 days after the 1st day of February".
But functions have to return just one value.
I'm not saying that SQL Server applies either of the above interpretations. What it does do, though, is ensures that if you add, say, 1 month onto a particular date, you can be sure that the resulting date falls in the following month.

How to group daily data on weekly basis using sql

I am trying to group the number of hours that employees worked for the last 4 weeks but I want to group them on a weekly basis. For example:
WEEK HOURS
Feb 24 to March 2 55
March 3 to March 9 40
March 10 to March 16 48
March 17 to March 23 37
This is what I have so far, please help. thanks
SET DATEFIRST 1
SELECT CAST(MIN( [DT]) AS VARCHAR(20))+' TO '+CAST (MAX([DT]) AS VARCHAR(20)) AS DATE,
SUM(HOURS) AS NUM_HRS
FROM MyTable
GROUP BY DATEPART(WEEK,[DT])
HAVING COUNT(DISTINCT[DT])=7
Create a Calendar auxilliary table, with Year, Month, Week, Date columns (you can also add holidays and other interesting stuff to it, it has many potential uses) and populate it for the period of interest.
After that, it's as easy as this:
SELECT sum(hours), cast(min(date) as varchar), cast(max(date) as varchar)
FROM Calendar c
LEFT OUTER JOIN MyTable h on h.Date = c.date
GROUP BY year, week
ORDER BY year, week
SET DATEFIRST 1
SELECT DATEPART(WEEK,DT) AS WEEK,
SUM(HOURS) AS NUM_HRS
FROM MyTable
WHERE DT >= DATEADD(WEEK, -4, GetDate()),
GROUP BY DATEPART(WEEK,[DT])
Try something like
SELECT
DATEADD(DD,
CONVERT(INT, (DATEDIFF(DD, '1/1/1900', t.DT)/7)) * 7,
'1/1/1900') [WeekBeginDate],
DATEADD(DD,
(CONVERT(INT, (DATEDIFF(DD, '1/1/1900', t.DT)/7)) * 7) + 6,
'1/1/1900') [WeekEndDate],
SUM(HOURS) AS NUM_HRS
FROM MyTable t
GROUP BY CONVERT(INT, DATEDIFF(DD, '1/1/1900', t.DT)/7)
Though this is the brute force trick, I think in your case it will work.
EDIT : Modified the query a little bit, the error was caused because of the order in which DATEDIFF calculates the difference.
Also here is a SQL FIDDLE with a working example.
EDIT 2 : Updated the Fiddle with the Date Format. To customize the date format, this article would help.

Sort by Date in SQL

I have a resources table, one of the fields is a date field with the Data Type of date. I want to have to following output:
Current month records (say May - year is not important)
Then the following (again, assuming May is the current month)
June Records
July Records
August Records
September Records
October Records
November Records
December Records
January Records
February Records
March Records
April Records
Come June, June is the current month and then the order would be:
July Records
August Records
...
Here is my SQL...I don't know how to ORDER the output to achieve the desired order (5,6,7,8,9,10,11,12,1,2,3,4):
SELECT
resource_id,
resource_title,
resource_summary,
resource_category,
resource_status,
resource_date,
DATEPART(month, resource_date) AS resource_month,
DATEPART(day, resource_date) AS resource_day
FROM dbo.resources
WHERE (resource_category = N'Quotes')
AND (resource_status <> N'Draft')
I found this possible solution for MySQL:
I need unusual ordering mysql results
but I'm missing something on my end.
ORDER BY
(MONTH(resource_date) - MONTH(GETDATE()) + 12) % 12,
DATEADD(year, YEAR(GETDATE()) - YEAR(resource_date), resource_date),
YEAR(resource_date)
The first term sets the primary order by the month of resource_date (the current month will be first, the previous one, last). The second term orders the timestamps within a month regardless of the year of the date. If your dates do not contain time parts or if the time parts are absolutely irrelevant, you could replace it with DAY(resource_date). Finally, the last term takes the year into account for otherwise identical dates (could also be simply resource_date).
Will it work for you?
ORDER BY
CASE DATEPART(month, resource_date)
WHEN 5 THEN 0
WHEN 6 THEN 1
... etc
END
I think something like this might be what you're looking for:
SELECT
resource_id,
resource_title,
resource_summary,
resource_category,
resource_status,
resource_date
FROM
dbo.resources
WHERE
resource_date >= DATE_FORMAT(NOW() ,'%Y-%m-01') AND
resource_date < DATE_FORMAT(DATE_ADD(NOW(), INTERVAL 1 YEAR) ,'%Y-%m-01')
ORDER BY
resource_date;
How 'bout ORDER BY (DATEPART(month,resource_date) - (DATEPART(month,getdate() -1)) % 12)
So in May (month 5), you order by the month in the row -6 (mod 12). So, June (month 6) would be 0, July (7) would be 1.
In June, July would be 0, etc.
You should be able to adapt the MySQL solution by using DATEPART in place of DATE_FORMAT:
SELECT resource_id, resource_title, resource_summary, resource_category, resource_status, resource_date, DATEPART(month, resource_date) AS resource_month, DATEPART(day, resource_date) AS resource_day
FROM dbo.resources
WHERE (resource_category = N'Quotes') AND (resource_status <> N'Draft')
ORDER BY DATEPART(month, resource_date) < DATEPART(month, GETDATE()),
DATEPART(month, resource_date)
I don't have SQL Server handy so I'm not sure if it will be happy with a boolean in the ORDER BY clause though. If it doesn't like the boolean ORDER BY, then a CASE should do the trick:
ORDER BY
CASE WHEN DATEPART(month, resource_date) < DATEPART(month, GETDATE())
THEN 0
ELSE 1
END,
DATEPART(month, resource_date)
I assume that there is a year within "resource_date" - isn't it?
In this case you can simply filter and order by
WHERE resource_date >= getdate()
AND resource_date < DATEADD(year,1,getdate())
ORDER BY resource_date;
If there is no year (or more exactly: different unknown years) you can do this:
ORDER BY
CASE
WHEN DATEADD(year,-year(resource_date),resource_date) <
DATEADD(year,-year(getdate()),getdate())
THEN 1
ELSE 0
END ASC,
DATEADD(year,-year(resource_date),resource_date);
Hope it helped ...