SQL Scalar UDF to get number of days in Year - tsql

I writing code to determine how many days in a year. I am trying to keep it really simple.
I found code that I think is very clean to determine a leap year. I am passing the inputted date using DATEPART(Y,#Year) to the leap year program and some how am not getting the correct results so I has to be in my SQL code to process the input date as the correct bit is returned.
Here is the code for the Leap Year:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[FN_Is_Leap_Year]
(
-- the parameters for the function here
#year int
)
RETURNS BIT
AS
BEGIN
RETURN (select case datepart(mm, dateadd(dd, 1, cast((cast(#year as varchar(4)) + '0228') as datetime)))
WHEN 2 THEN 1
ELSE 0 END)
END
Here is the code I wrote to process the input date & get the # days in a year:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[FN_Get_Days_In_Year]
(
#InputDT varchar(10)
)
RETURNS int
AS
BEGIN
DECLARE #Result int,
#Year int
Set #Result =
CASE
WHEN dbo.FN_Is_Leap_Year(Datepart(yyyy,#Year)) = 0 Then 365
WHEN dbo.FN_Is_Leap_Year(Datepart(yyyy,#Year)) = 1 Then 366
END
RETURN #Result
END

Got it working!!
GO
ALTER FUNCTION [dbo].[FN_Get_Days_In_Year]
(
#InputDT int
)
RETURNS varchar(3)
AS
BEGIN
Declare #Year int,
#RetVal bit,
#Result varchar(3)
Set #Year = datepart(yy, #InputDT)
Set #RetVal = dbo.FN_Is_Leap_Year(Datepart(yy,'2012'))
Set #Result = CASE #RetVal
WHEN 1 THEN 366
ELSE 365
End
Return #Result
END

Modified version of the above answer :
DECLARE #year INT,
#DaysInYear INT
SET #year = 2011
SELECT #DaysInYear = CASE DATEPART(mm, DATEADD(dd, 1, CAST((CAST(#year AS VARCHAR(4)) + '0228') AS DATETIME)))
WHEN 2 THEN 366 ELSE 365 END
SELECT #DaysInYear 'DaysInYear'

Related

How to create a function which will retrieve year, based on a certain logic

I need to create a function in DB2 which will retrieve year from the current date, based on a certain logic
If the number of the month of the current date is smaller and equal than 6 (=any month prior to June) then the previous year is the ‘reference year’
Else if the number of the month of the current date is larger than 6 (=any month after June!) then the current year is the ‘reference year’.
Examples:
The reference year for date ‘4/9/2019’ is 2018 , since 4 <= 6
The reference year for date ‘9/3/2019’ is 2019, since 9 > 6
Below is an example for the implementation for SQL Server:
CREATE FUNCTION dbo.getReferenceYear()
RETURNS int
AS
BEGIN
DECLARE #ret int;
SELECT #ret = MONTH(GETDATE())
IF (#ret <= 6)
SET #ret = (YEAR(GETDATE()) -1);
Else
SET #ret = (YEAR(GETDATE()) );
RETURN #ret;
END;
I need the same in db2.
Below is what I have tried
CREATE FUNCTION dbo.getReferenceYear()
RETURNS INT
BEGIN ATOMIC
DECLARE _month INT;
DECLARE _year INT;
SET _month = SELECT MONTH (current timestamp) FROM sysibm.sysdummy1
if(_month<=6)
SET _year = (SELECT YEAR (current timestamp) FROM sysibm.sysdummy1) -1
ELSE
SET _year = (SELECT YEAR (current timestamp) FROM sysibm.sysdummy1)
RETURN _year
END
Here is one way to do in in Db2-LUW:
CREATE or replace FUNCTION dbo.getReferenceYear()
RETURNS INT
BEGIN ATOMIC
declare v_nowts timestamp default current timestamp;
declare v_year int;
set v_year= year(v_nowts);
if ( month(v_nowts) <= 6 ) THEN
SET v_year = v_year -1;
END IF;
RETURN v_year ;
END
CREATE FUNCTION dbo.getReferenceYear()
RETURNS INT
as
BEGIN
DECLARE #month INT,#year INT;
SET #month = SELECT MONTH (ColumnName) FROM TableName
if(_month<=6)
SET #year = (SELECT YEAR (ColumnName) FROM TableName -1)
ELSE
SET #year = (SELECT YEAR (ColumnName) FROM TableName)
RETURN #year
END
Or if you don't have any column for the date and if you want to apply the same logic for the current date, then-
CREATE FUNCTION dbo.getReferenceYear()
RETURNS INT
as
BEGIN
DECLARE #month INT,#year INT;
SET #month =( SELECT MONTH (GETDATE()) )
if(#month<=6)
SET #year = (SELECT YEAR (GETDATE())-1)
ELSE
SET #year = (SELECT YEAR (GETDATE()) )
RETURN #year
END
I would do it like this
CREATE FUNCTION getReferenceYear()
RETURNS SMALLINT
RETURN YEAR(CURRENT DATE) - CASE WHEN MONTH(CURRENT DATE) <= 6 then 1 ELSE 0 END

Coverting/ Casting operators to integer

I want to convert/ cast these operators ( '/' and '*') if this is possible. Maybe you know how that works or you know what the internal coding of division and multiplication is?! Maybe then I can continue with that?
What I want to do is, based on the last number of the current system time, I want to decide if that number is odd or even, and then do a multiplication or division in the next calculations.
CREATE FUNCTION CalculateFactor()
RETURNS NVARCHAR(50)
AS
BEGIN
DECLARE #time DATETIME2(7)
DECLARE #length INT
DECLARE #value NVARCHAR(20)
DECLARE #operator NVARCHAR(20)
SET #time = SYSDATETIME()
SELECT #length = LEN(#time)
SELECT #value = RIGHT(#time, 1);
IF (#value % 2 = 0)
SET #operator = '*'
ELSE SET #operator = '/'
DECLARE #SQL NVARCHAR(20)
SET #SQL = '10' + #operator + '2' --I get only 10 / 2 and 10 * 2 because that are strings and that is why I cannot get a result of the operation, but I want 5 and 20
RETURN #SQL
END
GO

Conversion failed when converting date and/or time from character string - SQL Server 2008 R2

I am busy with a stored procedure to calculate production numbers of shifts. I already have an idea on how to do that but for some kind of strange reason I do not get an insert into with a variable time working. Below is query for the stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ProductionReport]
#filterStartTime datetime,
#filterEndTime datetime,
#machine varchar(10)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
CREATE TABLE #tempProductionTable(
id varchar(3),
ploeg varchar(3),
starttime2 datetime,
endtime2 datetime,
daynumber int)
declare #i int
, #SQLString varchar(400)
, #id varchar(3)
, #ploeg varchar(3)
, #starttime datetime
, #endtime datetime
set #i = 0
while #i < 16
begin
set #i = #i+1
set #id = #i
set #starttime = convert(datetime, #filterStartTime,110)
print #starttime
set #ploeg = '2'
SET #SQLString = 'INSERT INTO #tempProductionTable (id,ploeg,starttime2) values ('+#id+','+#ploeg+','+#starttime+')'
EXEC(#SQLString)
end
-- Insert statements for procedure here
SELECT * from #tempProductionTable
END
And this is the query for opening the stored procedure:
USE [NRPConfiguration]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[ProductionReport]
#filterStartTime = '2017-01-01 10:00:00.000',
#filterEndTime = N'2-1-2017 0:00',
#machine = N'ASM_008'
SELECT 'Return Value' = #return_value
GO
I already tried a lot of things but still can't get it working. For example when I manually insert a time than it is working. But when I want to do it with an variable it is not working also when I am using the convert function for it. What am I doing wrong?
I use SQL Server 2008 R2 for this.
Quit concatenating strings to executed dynamic sql, use sp_executesql instead.
Your error can be correct by specifying dates in ISO format (or in the format Dan Bracuk mentioned in his comment). e.g. '2017-04-01T23:59:59.363'
#BackToBasics : Dating Responsibly - Aaron Bertrand
Here is how you would use sp_executesql instead:
alter procedure [dbo].[ProductionReport] (
#filterStartTime datetime,
#filterEndTime datetime,
#machine varchar(10)
) as
begin;
-- set nocount on added to prevent extra result sets from
-- interfering with select statements.
set nocount on;
create table #tempProductionTable(
id varchar(3)
, ploeg varchar(3)
, starttime2 datetime
, endtime2 datetime
, daynumber int
);
declare #i int
, #params nvarchar(max)
, #sqlstring nvarchar(max)
, #id varchar(3)
, #ploeg varchar(3)
, #starttime datetime
, #endtime datetime;
set #params = '#id int, #ploeg varchar(3), #starttime datetime';
set #sqlstring = 'insert into #tempProductionTable (id,ploeg,starttime2) values (#id,#ploeg,#starttime);';
set #i = 0
while #i < 16
begin
set #i = #i+1
set #id = #i
set #starttime = convert(datetime, #filterStartTime,110)
set #ploeg = '2'
print #starttime
exec sp_executesql #sqlstring, #params, #id, #ploeg, #starttime;
end
-- Insert statements for procedure here
select * from #tempProductionTable
end;
go
rextester demo: http://rextester.com/KPBR1056

how to convert 3 integer to date format in SQL server 2008 r2?

There is following statements in my query:
declare #d int = day(getdate())
declare #m int = month(getdate())
declare #y int = year(getdate())
select #d,#m,#y
So I want to convert #d,#m,#y to date type(format) and use it as date parameter!
Thanks
Try this:
declare #d int = day(getdate())
declare #m int = month(getdate())
declare #y int = year(getdate())
DECLARE #myDate DATETIME
SET #myDate = CAST (#y AS NVARCHAR(4))+'-'+CAST (#m AS NVARCHAR(2))+'-'+CAST (#d AS NVARCHAR(2));
select #myDate
If u dont cast the values you will get some other date.
This will do it in a portable fashion:
select DATEADD(year,#y - 2000,DATEADD(month,#m - 1, DATEADD(day,#d - 1,
'20000101')))
However, if your motivation was just to get the current date without any time portion, I'd just do:
select DATEADD(day,DATEDIFF(day,0,GETDATE()),0)
Or even
select CONVERT(date,GETDATE())
select *
from WeatherForecast
where Cast( cast(year as nchar(4)) + '-' + cast(month as nchar(2)) + '-' + cast(day as nchar(2)) as date) between getdate() - 7 and getdate()

T-SQL How to check if DataTime contains a Date string?

I have a DateTime column row and I declare a date string:
Row:
2010-08-27 13:45:55
My string:
'2010-08-27'
How can I check if that string is in that row ?
I tried the following query:
declare #year as nvarchar(4)
declare #month as nvarchar(2)
declare #day as nvarchar(2)
set #year = '2010'
set #month = '08'
set #day = '23'
select * FROM [dbo].[customer_import] CsrImport
where
(YEAR(CsrImport.import_date) = #year
AND MONTH(CsrImport.import_date) = #month
AND DAY(CsrImport.import_date) = #day)
but I see that it returns all rows (even that are not contains that date)
Sql server : ISDATE (Transact-SQL)
----Invalid date
SELECT ISDATE('30/2/2007')
RETURNS : 0 (Zero)
----Valid date
SELECT ISDATE('12/12/20007)'
RETURNS : 1 (ONE)
----Invalid DataType
SELECT ISDATE('SQL')
RETURNS : 0 (Zero)
Like this, this will also be able to use the index, do not use function on the column itself..it is not SARGable!!
where import_date >= convert(datetime,#year + #month + #day)
and import_date < convert(datetime,#year + #month + #day) + 1
The best way for you would be to use dates and not 3 different parameters, what if someone passes in 13 for month?
Here is an example which checks that the values that are passed in can be converted to a date, if not it will show an error message
DECLARE #year AS NVARCHAR(4)
DECLARE #month AS NVARCHAR(2)
DECLARE #day AS NVARCHAR(2)
SET #year = '2010'
SET #month = '08'
SET #day = '23'
DECLARE #date DATETIME
IF ISDATE(#year + #month + #day) = 0
BEGIN
RAISERROR('values passed in are not a valid date',16,1)
RETURN
END
ELSE
BEGIN
SET #date = #year + #month + #day
END
SELECT * FROM [dbo].[customer_import] CsrImport
WHERE import_date >=#date
AND import_date < #date + 1
That should work, howabout if you make the values INTS
declare #year as INT
declare #month as INT
declare #day as INT
set #year = 2010
set #month = 08
set #day = 23
select * FROM [dbo].[customer_import] CsrImport
where
(YEAR(CsrImport.import_date) = #year
AND MONTH(CsrImport.import_date) = #month
AND DAY(CsrImport.import_date) = #day)
EDIT: Make sure all the statement is highlighted when you run it too. As simple as it seems, is it possible you mised the where clause if you highlighted the statement.
Just turn the datestring into a date (or datetime) variable and use a where clause:
Since your table has times in it, you have to strip them out or compare them to the midnioght before and after
Declare #myDate DateTime
Set #myDate = 'August 23 2010'
Select * FROM [dbo].[customer_import] CsrImport
Where DateDiff(day, myDate,import_date) = 0 -- Not Sargable
or
Declare #myDate DateTime
Set #myDate = 'August 23 2010'
Select * FROM [dbo].[customer_import] CsrImport
Where import_date) Between #mydate And #Mydate + 1 -- Sargable