Group by ISO Week and year [duplicate] - sql-server

I am currently working on creating my first Data_warehouse using sql-server
I have a Date dimension i want to populate it using SSIS it has a field called ISO_year
can somebody tell me how do i get it ?
i tried this query ::
select year(getdate()) -- but i dont think is this ISO_year ?
And i need to know which is best practice to load dimensions into DB using ssis ?
i reffered this http://michaelmorley.name/how-to/create-date-dimension-table-in-sql-server

Here is a function for iso_year, the logic behind it is that the thursday of the week from the parameter date determine the year:
CREATE FUNCTION [dbo].[f_isoyear]
(
#p_date datetime
)
RETURNS int
as
BEGIN
RETURN datepart(yy, dateadd(wk, datediff(d, 0, #p_date)/7, 3))
END

Here is a Connect item that requests a function to calculate ISO_YEAR.
DATEPART - ISO_YEAR for ISO_WEEK
In the workaround section you have this function that you can use.
CREATE FUNCTION [dbo].[ISOyear](#date DATETIME)
returns SMALLINT
AS
BEGIN
DECLARE #isoyear SMALLINT = CASE
WHEN Datepart(isowk, #date)=1
AND Month(#date)=12 THEN Year(#date)+1
WHEN Datepart(isowk, #date)=53
AND Month(#date)=1 THEN Year(#date)-1
WHEN Datepart(isowk, #date)=52
AND Month(#date)=1 THEN Year(#date)-1
ELSE Year(#date)
END;
RETURN #isoyear;
END;

Related

Find End Date of month (Exclude Sunday and Saturday)

I have wrote a script (from the internet) but it's not working because of some logical error I guess.
ALTER FUNCTION EstDateCheck (#CoustDesireddate varchar(10))
RETURNS varchar(20)
AS
BEGIN
declare #testDate Date = (SELECT STUFF(#CoustDesireddate, 4, 0, '01/'));
declare #lastWorkDay date = iif(DATEPART(WEEKDAY, EOMONTH(#testDate)) <= 5
,EOMONTH(#testDate)
,DATEADD(DAY, -(7-DATEPART(WEEKDAY, EOMONTH(#testDate))),EOMONTH(#testDate)))
RETURN #lastWorkDay
END
This is how I execute
select dbo.EstDateCheck('07/2022')
I would, honestly, consider creating a calendar table. There are plenty of examples out there, so I'm not going to cover how to create one; plus what columns you need vary.
What you will have, however, is a column to denote if the day is a weekday (and probably a working day), as well as what month and year it belongs to. As a result you can then simply get the last weekday with the following query:
SELECT MAX(CalendarDate)
FROM dbo.CalendarTable
WHERE CalendarYear = 2022
AND CalendarMonth = 7
AND Weekday = 1;
If you therefore wanted to do this as a function, you could use an inline table value function:
CREATE FUNCTION dbo.MonthLastWeekday (#Year int, #Month int)
RETURNS table
AS RETURN
SELECT MAX(CalendarDate) AS LastWeekday
FROM dbo.CalendarTable
WHERE CalendarYear = #Year
AND CalendarMonth = #Month
AND Weekday = 1;
And then you would call the function as follows:
SELECT LastWeekday
FROM dbo.MonthLastWeekday(#Year,#Month);

How to get the year of a date, depending on the weeknumber

I know how to get the year out of a date. But how can I get the year of a date, depending on the week number of that date?
Example: 28-12-2015 has week number 1 (ISO_WEEK). In this case, the week number does not belong to 2015, but 2016. Also: 1-1-2016: Weeknumber 53, so 1-1-2016 does not belong to 2016, but to 2015.
Is there a function to do this easily in SQL?
No there isn't, but I created it myself.
CREATE FUNCTION [dbo].[ISO_YEAR](#date DATETIME)
returns SMALLINT
AS
BEGIN
DECLARE #ISO_YEAR SMALLINT = CASE
WHEN DATEPART(ISO_WEEK, #date)=1
AND MONTH(#date)=12 THEN YEAR(#date)+1
WHEN DATEPART(ISO_WEEK, #date)=53
AND MONTH(#date)=1 THEN YEAR(#date)-1
WHEN DATEPART(ISO_WEEK, #date)=52
AND Month(#date)=1 THEN YEAR(#date)-1
ELSE YEAR(#date)
END;
RETURN #ISO_YEAR;
END;
As per your question it seems you have two different dates and you are not able to identify in which year this date belongs to.
I have a small example here:
DECLARE #Date datetime, #Date1 datetime
SET #Date = '2015-12-28'
SET #Date1 = '2016-01-01'
SELECT CASE WHEN datepart(Wk , #Date ) < datepart(Wk , #Date1 ) THEN (datepart(YEAR , #Date1 ) + 1) ELSE (datepart(YEAR , #Date1 )) END AS GETYEAR
OUTPUT:
2016
I storngly recommend that this is not a correct way to know the year. it is not a +/- 1 logic here. there are max 53 weeks every year and you should always get the year from date which you have.
refer fiddle:
http://sqlfiddle.com/#!3/9eecb7/4510

What is the equivalent of Oracle's LAST_DAY() function in SQL Server 2008?

I have used the LAST_DAY() function in Oracle like this:
Last_Day( to_date( '$pay_first_day' , 'YYYY-mm-dd') )
What do i have to do in SQL server 2008 R2 database to achieve the same result?
Try this one -
DECLARE #Date DATETIME
SELECT #Date = GETDATE()
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, #Date) + 1, 0) - 1
SQL Server 2012 introduces a new date function called EOMONTH which returns the last day of the month that contains the specified date, with an optional offset.
EOMONTH ( <start_date> [, <month_to_add> ] )
For instance
select EOMONTH('01/07/2018')
Would return
2018-01-31
-- Wrapping the answer in a function for seamless transition.
CREATE FUNCTION [dbo].[LAST_DAY]
(
#inDate DATETIME
)
RETURNS DATETIME
AS
BEGIN
RETURN DATEADD(MONTH, DATEDIFF(MONTH, 0, #inDate) + 1, 0) - 1
END
-- TO TEST: SELECT dbo.LAST_DAY(getDate()) as LastDayOfThisMonth
-- note: Please mark as answer if this helps you better then the one before.
Could you please try this, it should work as expected :
SELECT DATEADD (DAY, -1, DATEADD (MONTH, DATEDIFF (MONTH, 0, '$pay_first_day') + 1, 0))
It would return the last day equivalent of the given date in this format : '2013-02-28 00:00:00.000' if your $pay_first_day is in February, and it would return '2013-04-30 00:00:00.000' if your $pay_first_day is in April.
Here are two UDF for begin and end of month.
CREATE FUNCTION dbo.End_of_month (#Date datetime)
RETURNS datetime AS
BEGIN
DECLARE #ret datetime
SET #Ret=DATEADD(DAY,-DAY(#Date)+1,#Date);
SET #Ret=DATEADD(Month,1,#Ret);
SET #Ret=DATEADD(Day,-1,#Ret);
RETURN(#Ret)
END
CREATE FUNCTION dbo.Begin_of_month (#Date datetime)
RETURNS datetime AS
BEGIN
DECLARE #ret datetime
SET #Ret=DATEADD(DAY,-DAY(#Date)+1,#Date);
RETURN(#Ret)
END

How to solve the date comparison issue in SQL Server?

I am using the following way to compare two dates:
if CONVERT(varchar(20), #ScheduleDate, 101) >= CONVERT(varchar(20), #CurrentDateTime, 101)
This is working fine for the current year, but when the comes in yearly like one date is 12/31/2012 and 1/1/2013 then its not working.
Please help me how can I resolve this.
why do you comparing strings?
you can compare dates
if #ScheduleDate >= #CurrentDateTime
but if your date contains time, I usually do
if convert(nvarchar(8), #ScheduleDate, 112) >= convert(nvarchar(8), #CurrentDateTime, 112)
112 datetime format is YYYYMMDD so it's good for compare dates
You have to remember that string comparison is from left to right, so "1/...." is smaller than "12/...".
You need to use DATETIME comparisons, not string comparison.
Something like
DECLARE #ScheduleDate DATETIME = '1/1/2013',
#CurrentDateTime DATETIME = '12/31/2012'
IF (#ScheduleDate >= #CurrentDateTime)
BEGIN
SELECT #ScheduleDate, #CurrentDateTime
END
DECLARE #ScheduleDateString VARCHAR(20) = '1/1/2013',
#CurrentDateTimeString VARCHAR(20) = '12/31/2012'
IF (CONVERT(DATETIME,#ScheduleDateString,101)>=CONVERT(DATETIME,#CurrentDateTimeString,101))
BEGIN
SELECT CONVERT(DATETIME,#ScheduleDateString,101),CONVERT(DATETIME,#CurrentDateTimeString,101)
END
SQL Fiddle DEMO
Note that if the variables are already datetimes, you do not need to convert them.
Assuming that both variables are currently DateTime variables, can't you just compare them without converting to strings?
declare #ScheduleDate DATETIME, #CurrentDateTime DATETIME
SET #ScheduleDate = '1 Jan 2013'
SET #CurrentDateTime = GetDate()
IF (#ScheduleDate >= #CurrentDateTime)
BEGIN
SELECT 'Do Something'
END
ELSE
BEGIN
SELECT 'Do Something Else'
END
when you use CONVERT(nvarchar(8), #ScheduleDate, 112) function it's return string instead of date.
so,
Use "112" DateFormat in Sql Server it's return string in "YMD" format without any sepration.
compare that string in your query and get desire output.
Such as "if CONVERT(nvarchar(8), #ScheduleDate, 112) >= CONVERT(nvarchar(8), #CurrentDateTime, 112)"
I would not use CONVERT to compare formatted strings. It is slow (well, more like microseconds, but still)
I use a UDF for SQL prior to version 2008
CREATE FUNCTION [dbo].[DateOnly] (#Date DateTime)
RETURNS Datetime AS
BEGIN
Return cast (floor (cast (#Date as float)) as DateTime)
END
and for versions >=2008 this approach
select convert(#MyDateTime as DATE)
Of course, you can compare datetime values directly, but to know whether two datetime values are on the same date (ignoring the time component), the above versions have proven to be effectivy.
Date : From and To with following format
from_Date# = #dateformat("#form.from#", "mm/dd/yyyy")
to_Date# = #dateformat("#now()#" + 1, "mm/dd/yyyy")
In SQL Statement
WHERE a.DateCreated >= CAST ('#from_date#' AS DATE) and a.DateCreated <= CAST('#to_date#' AS DATE)
This is working fine without any cast of original date time column

SQL Server Indexes of DateTime Parts such as YEAR, MONTH

Is it possible to have indexes on DateTime parts such as DATEPART(YEAR, bp.[CreatedOn]) and DATEPART(MONTH, bp.[CreatedOn])? For example, I have the following T-SQL query:
DECLARE #year AS INT = 2012;
DECLARE #month AS INT = 8;
SELECT bp.Title, bp.CreatedOn FROM BlogPosts bp
WHERE (DATEPART(YEAR, bp.[CreatedOn]) = #year) AND (DATEPART(MONTH, bp.[CreatedOn]) = #month)
ORDER BY bp.CreatedOn;
And this is the execution plan I have: https://gist.github.com/3551450
Currently, there are not many records so it is not a big problem in terms of perf but the records will grow over the time.
You'd better construct criterion using datetime field:
declare #startMonth datetime = '20120801'
SELECT bp.Title, bp.CreatedOn
FROM BlogPosts bp
WHERE bp.[CreatedOn] >= #startMonth
AND bp.[CreatedOn] < dateadd (month, 1, #startMonth)
ORDER BY bp.CreatedOn;
This way query executor will be able to use index on CreatedOn.
Yes is it possible to put index on year and month. Here is an example:
create table testt(d datetime)
alter table testt add year as year(d) PERSISTED -- after marc_s advise. Thx
alter table testt add month as month(d) PERSISTED --
create index idx_year on testt(year)
create index idx_month on testt(month)
However I would always use a variation of Nikola's solution, so +1 to Nikola.
This is how you can rewrite month and year into a date:
DECLARE #year AS INT = 2012;
DECLARE #month AS INT = 8;
DECLARE #from DATE = dateadd(month, (#year-1900)*12 + #month - 1, 0)
I suggest you store date parts on different fields. Clearly this is a requirement which exist in your domain as such needs to be part of your model.
What you lose is that you have to construct the datetime for every model you load or you set the value but that would be a few CPU cycles.

Resources