How to pass parameter values to SQL query

  • Hi,

    I'm trying to run a query which sums up all transactions to arrive at today's inventory holding.

    I'm now trying to get the inventory holding for the end of each month.

    I'm simplifying the problem here so I can't use grouping etc.

    I have an SQL Statement like the below:

    DECLARE @CutOffDate varchar (6);

    SET @CutOffDate = '201501';

    INSERT INTO testtable (Quantity, YearMonth)

    SELECT SUM(QUANTITY) AS TotalQty, @CutOffDate

    FROM ICIVAL

    WHERE LEFT(TRANSDATE,6) = @CutOffDate

    I have another table containing the last 12 months in this format: 201601, 201512, 201511 etc.

    I now want to run the above statement 12 times for each of the last 12 months.

    I think I need to use a stored procedure but don't know how to pass the parameter dynamically.

    Would appreciate any help.

    Thanks.

  • Hi,

    You just call the stored procedure with parameter after the procedure name as in the following example:

    CREATE PROCEDURE MyProc

    @CutOffDate varchar(6)

    AS

    INSERT INTO testtable (Quantity, YearMonth)

    SELECT SUM(QUANTITY) AS TotalQty, @CutOffDate

    FROM ICIVAL

    WHERE LEFT(TRANSDATE,6) = @CutOffDate

    GO

    DECLARE @CutOffDate varchar (6);

    SET @CutOffDate = '201501';

    EXEC MyProc @CutOffdate

  • Thank you for your prompt reply.

    The issue I have is that instead of using a fixed value for @CutOffDate I need to run my query for all the 'YearMonth' from another table.

    SET @CutOffDate = 'SELECT YearMonth FROM Past12Months'; does not work.

    It should run the stored procedure for all 'YearMonth' in the table 'Past12Monts'.

    CREATE PROCEDURE MyProc

    @CutOffDate varchar(6)

    AS

    INSERT INTO testtable (Quantity, YearMonth)

    SELECT SUM(QUANTITY) AS TotalQty, @CutOffDate

    FROM ICIVAL

    WHERE LEFT(TRANSDATE,6) = @CutOffDate

    GO

    DECLARE @CutOffDate varchar (6);

    SET @CutOffDate = 'SELECT YearMonth FROM Past12Months';

    EXEC MyProc @CutOffdate

  • Sorry, I misunderstood. Creating a function to do the work could be the answer, something like the following:

    CREATE FUNCTION MyFunc (@CutOffDate varchar(6))

    RETURNS INT

    AS

    BEGIN

    DECLARE @Qty INT

    SELECT @Qty = SUM(QUANTITY)

    FROM ICIVAL

    WHERE LEFT(TRANSDATE,6) = @CutOffDate

    RETURN @Qty

    END

    GO

    INSERT INTO testtable (Quantity, YearMonth)

    SELECT MyFunc(YearMonth), YearMotnh FROM Past12Months

  • You may wish to opt for a iTVF or APPLY instead of scalar function for better performance.

  • Thanks. Got it to work now.

  • Sorry, too quick.

    How would I return multiple columns from the fucntion, i.e. not only quantity, but value also?

    Can I specify what columns the function should return?

  • boettger.andreas (1/21/2016)


    Sorry, too quick.

    How would I return multiple columns from the fucntion, i.e. not only quantity, but value also?

    Can I specify what columns the function should return?

    Convert the function to an Inline Table Valued Function (iTVF) which will allow you to return any number of columns you require. The iTVF simply RETURNS TABLE so whatever columns you define in the SELECT it returns will come back from the function, ie no need to explicitly define the shape of the resultset ahead of time. iTVFs perform and scale better than Multi-statement Table Valued Functions (mTVF) and Scalar Valued Functions (SVF).

    There are no special teachers of virtue, because virtue is taught by the whole community.
    --Plato

  • 1) NEVER EVER use a scalar UDF if you can avoid it. HORRIBLY BAD STUFF!!!!!!!!

    2) NEVER wrap a function around a column in a WHERE clause if you can avoid it!!!!! In this case a LIKE should work, right?? That is SARGable, seekable (where appropriate), gets good estimates, etc.

    3) NEVER store a date as a string if you can avoid it!! So much would be better if you did that here!!

    Best,
    Kevin G. Boles
    SQL Server Consultant
    SQL MVP 2007-2012
    TheSQLGuru on googles mail service

  • Thanks. I've got it now with iTVF and CROSS APPLY

  • boettger.andreas (1/21/2016)


    Thanks. I've got it now with iTVF and CROSS APPLY

    Great. Can we see your code, please? A whole lot of people end up writing mTVFs instead of iTVFs.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Sure.

    ALTER FUNCTION [dbo].[ICAgeingFuncT]

    (

    @CutOffDate varchar(6)

    )

    RETURNS TABLE

    AS

    RETURN

    (

    SELECT SUM(TRANSCOST) AS ItemValue, SUM(Quantity) AS Qty

    FROM ICIVAL

    WHERE LEFT(TRANSDATE,6) <= @CutOffDate

    );

    SELECT a.ItemValue, a.Qty, p.YearMonth, p.Period FROM Past12Months as p

    CROSS APPLY dbo.ICAgeingFuncT(p.YearMonth) As a

  • boettger.andreas (1/21/2016)


    Sure.

    ALTER FUNCTION [dbo].[ICAgeingFuncT]

    (

    @CutOffDate varchar(6)

    )

    RETURNS TABLE

    AS

    RETURN

    (

    SELECT SUM(TRANSCOST) AS ItemValue, SUM(Quantity) AS Qty

    FROM ICIVAL

    WHERE LEFT(TRANSDATE,6) <= @CutOffDate

    );

    SELECT a.ItemValue, a.Qty, p.YearMonth, p.Period

    FROM Past12Months as p

    CROSS APPLY dbo.ICAgeingFuncT(p.YearMonth) As a

    There could be a way to design your iTVF that would allow you to do away with the LEFT-function that wraps TRANSDATE. Wrapping a column with a function can hurt performance pretty bad depending on the schema. Is it correct that @CutoffDate will be a date formatted as YYYYMM? Could you provide the DDL for the table ICIVAL and Past12Months including index and constraint definitions?

    There are no special teachers of virtue, because virtue is taught by the whole community.
    --Plato

  • Yes, @CutOffDate is in the format 'YYYYMM'

    Past12Months is a view.

    SELECTLEFT(CAST(CONVERT(varchar(8), DATEADD(MONTH, number, LEFT(CAST(CONVERT(varchar(8), DATEADD(MONTH, - 11, GETDATE()), 112) AS INT), 6) + '01'), 112) AS INT), 6) AS YearMonth,

    number + 1 AS Period

    FROM master.dbo.spt_values AS x

    WHERE (type = 'P') AND (number <= DATEDIFF(MONTH, LEFT(CAST(CONVERT(varchar(8), DATEADD(MONTH, - 11, GETDATE()), 112) AS INT), 6) + '01', LEFT(CAST(CONVERT(varchar(8), DATEADD(MONTH, - 0, GETDATE()), 112) AS INT), 6) + '01'))

    The DDL for ICIVAL is below.

    CREATE TABLE [dbo].[ICIVAL](

    [ACCTSET] [char](6) NOT NULL,

    [LOCATION] [char](6) NOT NULL,

    [ITEMNO] [char](24) NOT NULL,

    [FISCYEAR] [char](4) NOT NULL,

    [FISCPERIOD] [smallint] NOT NULL,

    [TRANSDATE] [decimal](9, 0) NOT NULL,

    [DAYENDSEQ] [int] NOT NULL,

    [ENTRYSEQ] [int] NOT NULL,

    [LINENO] [smallint] NOT NULL,

    [AUDTDATE] [decimal](9, 0) NOT NULL,

    [AUDTTIME] [decimal](9, 0) NOT NULL,

    [AUDTUSER] [char](8) NOT NULL,

    [AUDTORG] [char](6) NOT NULL,

    [CATEGORY] [char](6) NOT NULL,

    [DOCNUM] [char](22) NOT NULL,

    [TRANSTYPE] [smallint] NOT NULL,

    [UNIT] [char](10) NOT NULL,

    [QUANTITY] [decimal](19, 4) NOT NULL,

    [CONVERSION] [decimal](19, 6) NOT NULL,

    [TRANSCOST] [decimal](19, 3) NOT NULL,

    [STKQTY] [decimal](19, 4) NOT NULL,

    [OPTAMT] [decimal](19, 3) NOT NULL,

    [APP] [char](2) NOT NULL,

    [STOCKUNIT] [char](10) NOT NULL,

    [DEFPRICLST] [char](6) NOT NULL,

    [TOTALCOST] [decimal](19, 3) NOT NULL,

    [RECENTCOST] [decimal](19, 6) NOT NULL,

    [COST1] [decimal](19, 6) NOT NULL,

    [COST2] [decimal](19, 6) NOT NULL,

    [LASTCOST] [decimal](19, 6) NOT NULL,

    [STDCOST] [decimal](19, 6) NOT NULL,

    [COSTUNIT] [char](10) NOT NULL,

    [COSTCONV] [decimal](19, 6) NOT NULL,

    [TOTALQTY] [decimal](19, 4) NOT NULL,

    [PRICELIST] [char](6) NOT NULL,

    [PRICEDECS] [smallint] NOT NULL,

    [BASEPRICE] [decimal](19, 6) NOT NULL,

    [BASEUNIT] [char](10) NOT NULL,

    [BASECONV] [decimal](19, 6) NOT NULL,

    [DETAILNUM] [smallint] NOT NULL,

    [COMPNUM] [int] NOT NULL,

    [DATEBUS] [decimal](9, 0) NOT NULL,

    CONSTRAINT [ICIVAL_KEY_0] PRIMARY KEY CLUSTERED

    (

    [ACCTSET] ASC,

    [LOCATION] ASC,

    [ITEMNO] ASC,

    [FISCYEAR] ASC,

    [FISCPERIOD] ASC,

    [TRANSDATE] ASC,

    [DAYENDSEQ] ASC,

    [ENTRYSEQ] ASC,

    [LINENO] ASC

    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

    ) ON [PRIMARY]

    GO

    SET ANSI_PADDING OFF

    GO

    SET ANSI_PADDING ON

    GO

    /****** Object: Index [KEY_1] Script Date: 22/01/2016 12:09:07 PM ******/

    CREATE NONCLUSTERED INDEX [KEY_1] ON [dbo].[ICIVAL]

    (

    [LOCATION] ASC,

    [ITEMNO] ASC

    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

    GO

    /****** Object: Index [KEY_2] Script Date: 22/01/2016 12:09:07 PM ******/

    CREATE NONCLUSTERED INDEX [KEY_2] ON [dbo].[ICIVAL]

    (

    [DAYENDSEQ] ASC,

    [ENTRYSEQ] ASC,

    [LINENO] ASC

    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

    GO

    SET ANSI_PADDING ON

    GO

    /****** Object: Index [KEY_3] Script Date: 22/01/2016 12:09:07 PM ******/

    CREATE NONCLUSTERED INDEX [KEY_3] ON [dbo].[ICIVAL]

    (

    [ITEMNO] ASC,

    [LOCATION] ASC,

    [FISCYEAR] ASC,

    [FISCPERIOD] ASC

    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

    GO

    SET ANSI_PADDING ON

    GO

    /****** Object: Index [KEY_4] Script Date: 22/01/2016 12:09:07 PM ******/

    CREATE NONCLUSTERED INDEX [KEY_4] ON [dbo].[ICIVAL]

    (

    [ACCTSET] ASC,

    [LOCATION] ASC,

    [ITEMNO] ASC,

    [FISCYEAR] ASC,

    [FISCPERIOD] ASC,

    [TRANSTYPE] ASC,

    [TRANSDATE] ASC,

    [DOCNUM] ASC

    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

    GO

  • Funky stuff. Thanks for posting it. I would not expect anything but a scan out of the iTVF query plan even if you could remove the function. If you are in need of improving performance you could try adding a computed column to ICIVAL as LEFT(TRANSDATE,6) and then index the computed column to maybe speed up the query in the iTVF. Without knowing more about the data I could not attempt to flip the WHERE-clause or iTVF API to get rid of the function around TRANSDATE.

    What I was hoping to see was a CHAR(8) for TRANSDATE. I must say, I did not expect a DECIMAL(9,0). Any idea why it is 9 digits? If anything I would have thought 8 for YYYYMMDD or 12 for YYYYMMDDHHMM or even 14 for YYYYMMDDHHMMSS, but not 9. Is there a prescribed data-format in that column?

    There are no special teachers of virtue, because virtue is taught by the whole community.
    --Plato

Viewing 15 posts - 1 through 15 (of 27 total)

You must be logged in to reply to this topic. Login to reply