Reputation: 21895
Can I call a function that is not defined from a Stored Procedure ?
Consider we have a Stored Procedure that looks like that :
CREATE PROCEDURE [dbo].[stp__getClients]
AS
BEGIN
SET NOCOUNT ON;
Select Id,Name,Status ,
(CASE WHEN Status = 3 then run_date_calc(FromDate , ToDate) else ''
end) as DateRangeDesc
From ClientsTbl
...
END
GO
I want to add another property to the Select
like that :
(CASE WHEN Status = 3 then run_date_calc(FromDate , ToDate) else '' end)
We want to create a function inside the SP called run_date_calc
that
will get two dates and return a string with its range description
looks like :
declare @d1 datetime, @d2 datetime, @year int, @month int, @d int
set @d1 = '2009-09-24'
set @d2 = '2012-04-23'
set @year = datediff(year, @d1, @d2) - 1
set @month = datediff(month, dateadd(year, @year, @d1), @d2)
if dateadd(month, @month, dateadd(year, @year, @d1)) > @d2 set @month = @month - 1
set @d = datediff(day, dateadd(month, @month, dateadd(year, @year, @d1)), @d2)
print cast(@year as nvarchar) + ' year(s) ' + cast(@month as nvarchar) + ' month(s) and ' + cast(@d as nvarchar) + ' day(s)'
Is it possible to make an "inside function" and use it inside the SP , without creating it in the DB ?
Thanks
Upvotes: 0
Views: 584
Reputation: 2191
As you were informed, you can't define a function inside an SP. Besides, your function is incorrect. Look at my solution:
declare @d1 datetime, @d2 datetime, @year int, @month int, @d int
set @d1 = '2009-09-24'
set @d2 = '2012-04-23'
SET @year = NULLIF(DATEDIFF(year, @d1, @d2), 0)
IF @year IS NOT NULL AND DATEADD(year, @year, @d1) > @d2
SET @year = NULLIF(@year - 1, 0)
SET @month = NULLIF(DATEDIFF(month, DATEADD(year, ISNULL(@year, 0), @d1), @d2), 0)
IF DATEADD(month, ISNULL(@month, 0), DATEADD(year, ISNULL(@year, 0), @d1)) > @d2
set @month = NULLIF(@month - 1, 0)
set @d = DATEDIFF(day, DATEADD(month, ISNULL(@month, 0), DATEADD(year, ISNULL(@year, 0), @d1)), @d2)
SELECT ISNULL(cast(@year as nvarchar) + ' year(s) ', '') + ISNULL(cast(@month as nvarchar) + ' month(s) and ', '') + cast(@d as nvarchar) + ' day(s)'
Instead of using a function you could use CASE
statement, but in my opinion, it looks terrible:
SELECT
--Years
ISNULL(cast(
CASE WHEN DATEADD(year, ISNULL(NULLIF(DATEDIFF(year, @d1, @d2), 0), 0), @d1) > @d2
THEN NULLIF(DATEDIFF(year, @d1, @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(year, @d1, @d2), 0)
END
AS VARCHAR) + ' year(s) ', '')
--Months
+ ISNULL(cast(
CASE WHEN DATEADD(month, ISNULL(NULLIF(DATEDIFF(month, DATEADD(year, ISNULL(CASE WHEN DATEADD(year, ISNULL(NULLIF(DATEDIFF(year, @d1, @d2), 0), 0), @d1) > @d2
THEN NULLIF(DATEDIFF(year, @d1, @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(year, @d1, @d2), 0)
END, 0), @d1), @d2), 0), 0), DATEADD(year, ISNULL(CASE WHEN DATEADD(year, ISNULL(NULLIF(DATEDIFF(year, @d1, @d2), 0), 0), @d1) > @d2
THEN NULLIF(DATEDIFF(year, @d1, @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(year, @d1, @d2), 0)
END, 0), @d1)) > @d2
THEN NULLIF(DATEDIFF(month, DATEADD(year, ISNULL(CASE WHEN DATEADD(year, ISNULL(NULLIF(DATEDIFF(year, @d1, @d2), 0), 0), @d1) > @d2
THEN NULLIF(DATEDIFF(year, @d1, @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(year, @d1, @d2), 0)
END, 0), @d1), @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(month, DATEADD(year, ISNULL(CASE WHEN DATEADD(year, ISNULL(NULLIF(DATEDIFF(year, @d1, @d2), 0), 0), @d1) > @d2
THEN NULLIF(DATEDIFF(year, @d1, @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(year, @d1, @d2), 0)
END, 0), @d1), @d2), 0)
END
AS VARCHAR) + ' month(s) ', '')
--Days
+ cast(DATEDIFF(day, DATEADD(month, ISNULL(CASE WHEN DATEADD(month, ISNULL(NULLIF(DATEDIFF(month, DATEADD(year, ISNULL(CASE WHEN DATEADD(year, ISNULL(NULLIF(DATEDIFF(year, @d1, @d2), 0), 0), @d1) > @d2
THEN NULLIF(DATEDIFF(year, @d1, @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(year, @d1, @d2), 0)
END, 0), @d1), @d2), 0), 0), DATEADD(year, ISNULL(CASE WHEN DATEADD(year, ISNULL(NULLIF(DATEDIFF(year, @d1, @d2), 0), 0), @d1) > @d2
THEN NULLIF(DATEDIFF(year, @d1, @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(year, @d1, @d2), 0)
END, 0), @d1)) > @d2
THEN NULLIF(DATEDIFF(month, DATEADD(year, ISNULL(CASE WHEN DATEADD(year, ISNULL(NULLIF(DATEDIFF(year, @d1, @d2), 0), 0), @d1) > @d2
THEN NULLIF(DATEDIFF(year, @d1, @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(year, @d1, @d2), 0)
END, 0), @d1), @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(month, DATEADD(year, ISNULL(CASE WHEN DATEADD(year, ISNULL(NULLIF(DATEDIFF(year, @d1, @d2), 0), 0), @d1) > @d2
THEN NULLIF(DATEDIFF(year, @d1, @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(year, @d1, @d2), 0)
END, 0), @d1), @d2), 0)
END, 0), DATEADD(year, ISNULL(CASE WHEN DATEADD(year, ISNULL(NULLIF(DATEDIFF(year, @d1, @d2), 0), 0), @d1) > @d2
THEN NULLIF(DATEDIFF(year, @d1, @d2) - 1, 0)
ELSE NULLIF(DATEDIFF(year, @d1, @d2), 0)
END , 0), @d1)), @d2) as nvarchar) + ' day(s)'
Upvotes: 1
Reputation: 69594
Create a function in the database like this...
CREATE FUNCTION dbo.run_date_calc
(
@d1 datetime
, @d2 datetime
)
RETURNS VARCHAR(100)
AS
BEGIN
Declare @year int, @month int, @d int;
SET @year = datediff(year, @d1, @d2) - 1
SET @month = datediff(month, dateadd(year, @year, @d1), @d2)
IF dateadd(month, @month, dateadd(year, @year, @d1)) > @d2 set @month = @month - 1
set @d = datediff(day, dateadd(month, @month, dateadd(year, @year, @d1)), @d2)
RETURN ( cast(@year as varchar(10)) + ' year(s) '
+ cast(@month as varchar(10)) + ' month(s) and '
+ cast(@d as varchar(10)) + ' day(s)'
)
END
GO
And then simply call if from your proc
CREATE PROCEDURE [dbo].[stp__getClients]
AS
BEGIN
SET NOCOUNT ON;
Select Id,Name,Status ,
(CASE WHEN Status = 3 then dbo.run_date_calc(FromDate , ToDate) else ''
end) as DateRangeDesc
From ClientsTbl
...
END
GO
Upvotes: 1
Reputation: 96038
You can't "create" or define a function inside an SP, no. You'll have to create it on the/a database and then reference the object you created.
If, for some odd reason you don't want the object to remain, you could CREATE
it in TempDB, use it, and then DROP
it (but this would mean the SP cannot be run by two users simultaneously, as the object would already exist).
Just create it permanently.
Upvotes: 1