JAN
JAN

Reputation: 21895

Call a function from Stored Procedure

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

Answers (3)

Denis Rubashkin
Denis Rubashkin

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

M.Ali
M.Ali

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

Thom A
Thom A

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

Related Questions