What's the best way to pass parameter into a dynamic sql in my case? Thanks.

  • My final dynamic @sql would be:

    Select DocID, Code, Ref, Title, DocType, FileName, InitialSignOffDate, LastReviewDate, NextReviewDate, Due = Replace(@Due, 'in', 'Within'), DueValue, SA, Type, Category, Division, ITSDivision, Contact, Phone) From ##temp where DueValue <= 60 Order by NextReviewDate ASC

    I am running it by:

    exec (@sql)

    But it throws me error that @Due is not defined. In this case, how do I revise my code? Thanks. The @sql was built through lots of other codes, I want the new exec be as simple as possible and no need to do too much on @sql.

  • You'd have to define the variable inside the scope of the Exec command in order to do it that way. You're better off using sp_executeSQL instead.

    EXEC sp_executeSQL 'Select DocID, Code, Ref, Title, DocType, FileName, InitialSignOffDate, LastReviewDate, NextReviewDate, Due = Replace(@Due, 'in', 'Within'), DueValue, SA, Type, Category, Division, ITSDivision, Contact, Phone) From ##temp where DueValue <= 60 Order by NextReviewDate ASC',

    '@Due VARCHAR(1000)',@Due;

    Define @Due in the second piece there the same way you do in the proc/script that runs this command.

    Using sp_executeSQL this way helps prevent SQL injection attacks.

    Specifics on sp_executeSQL can be found here: http://msdn.microsoft.com/en-us/library/ms188001.aspx

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • GSquared (11/6/2012)


    You'd have to define the variable inside the scope of the Exec command in order to do it that way. You're better off using sp_executeSQL instead.

    EXEC sp_executeSQL 'Select DocID, Code, Ref, Title, DocType, FileName, InitialSignOffDate, LastReviewDate, NextReviewDate, Due = Replace(@Due, 'in', 'Within'), DueValue, SA, Type, Category, Division, ITSDivision, Contact, Phone) From ##temp where DueValue <= 60 Order by NextReviewDate ASC',

    '@Due VARCHAR(1000)',@Due;

    Define @Due in the second piece there the same way you do in the proc/script that runs this command.

    Using sp_executeSQL this way helps prevent SQL injection attacks.

    Specifics on sp_executeSQL can be found here: http://msdn.microsoft.com/en-us/library/ms188001.aspx

    Thanks for the quick reply. Much appreciated.

    I tried to do this:

    EXEC sp_executeSQL @sql, @Due

    It throws me new error:

    Msg 214, Level 16, State 2, Procedure sp_executesql, Line 1

    Procedure expects parameter '@statement' of type 'ntext/nchar/nvarchar'.

    There is no parameter of @statement

  • halifaxdal (11/6/2012)


    GSquared (11/6/2012)


    You'd have to define the variable inside the scope of the Exec command in order to do it that way. You're better off using sp_executeSQL instead.

    EXEC sp_executeSQL 'Select DocID, Code, Ref, Title, DocType, FileName, InitialSignOffDate, LastReviewDate, NextReviewDate, Due = Replace(@Due, 'in', 'Within'), DueValue, SA, Type, Category, Division, ITSDivision, Contact, Phone) From ##temp where DueValue <= 60 Order by NextReviewDate ASC',

    '@Due VARCHAR(1000)',@Due;

    Define @Due in the second piece there the same way you do in the proc/script that runs this command.

    Using sp_executeSQL this way helps prevent SQL injection attacks.

    Specifics on sp_executeSQL can be found here: http://msdn.microsoft.com/en-us/library/ms188001.aspx

    Thanks for the quick reply. Much appreciated.

    I tried to do this:

    EXEC sp_executeSQL @sql, @Due

    It throws me new error:

    Msg 214, Level 16, State 2, Procedure sp_executesql, Line 1

    Procedure expects parameter '@statement' of type 'ntext/nchar/nvarchar'.

    There is no parameter of @statement

    The error message states it about as clear as it could be. Change your datatype of @sql to nvarchar and you should be good to go.

    _______________________________________________________________

    Need help? Help us help you.

    Read the article at http://www.sqlservercentral.com/articles/Best+Practices/61537/ for best practices on asking questions.

    Need to split a string? Try Jeff Modens splitter http://www.sqlservercentral.com/articles/Tally+Table/72993/.

    Cross Tabs and Pivots, Part 1 – Converting Rows to Columns - http://www.sqlservercentral.com/articles/T-SQL/63681/
    Cross Tabs and Pivots, Part 2 - Dynamic Cross Tabs - http://www.sqlservercentral.com/articles/Crosstab/65048/
    Understanding and Using APPLY (Part 1) - http://www.sqlservercentral.com/articles/APPLY/69953/
    Understanding and Using APPLY (Part 2) - http://www.sqlservercentral.com/articles/APPLY/69954/

  • First, is @SQL defined as varchar, or nvarchar? Needs to be unicode for this (nvarchar).

    Second, you need to provide sp_executeSQL with (at least) 3 things in order to use parameters in it:

    The command

    A list of the parameters in it

    The values.

    Example:

    DECLARE @SQL NVARCHAR(MAX) = 'SELECT @val as Val;', @val INT = 1;

    EXEC sp_executeSQL @SQL, N'@Val INT', @val;

    Example 2:

    DECLARE @SQL NVARCHAR(MAX) = 'SELECT @val as Val, @Val2 as Val2;';

    EXEC sp_executeSQL @SQL, N'@Val INT, @Val2 INT', 1, 2;

    The first value passed to sp_executeSQL is the command to be executed, which has to be defined as an nvarchar string. It can be a variable, or a fixed-value, but not a constructor.

    Wrong example:

    EXEC sp_executeSQL N'SELECT ' + CAST(1 AS NCHAR(1))

    That won't work because it use a string-constructor, instead of a variable or a fixed string.

    If you look at the second example, you'll see a list of the parameter values at the end of the call to sp_executeSQL, in the form of "1,2". Right before that, it has a string that defines the parameters, just like at the beginning of a stored procedure. Again, this has to be Unicode (nchar/nvarchar), and it can be either a variable or a fixed string, but not a string-constructor. Same as the SQL command.

    The other way to build variable values into dynamic SQL is simpler, but less safe and effective.

    DECLARE @Val1 VARCHAR(1000) = '1';

    DECLARE @SQL VARCHAR(100);

    SET @SQL = 'SELECT ' + @Val1 + ' AS Val;';

    EXEC (@SQL);

    That example treats @Val1 as an input parameter, concatenates it into the @SQL string, then executes the string.

    Why is that a bad idea? Because what if someone provides this as the "value" for @Val1 "hello' or 1=1;DROP TABLE dbo.Users--"? Run that in an Exec() call, and you may very well end up with a table being dropped. This is called "SQL injection", and it is one of the most common tools used by hackers.

    If someone does that to parameterized calls to sp_executeSQL, it's treated as an input, and the drop table part is just a string, it doesn't get executed, so your database is safe. That's one of the main differences between Exec() and sp_executeSQL.

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • Goodness me! Thank you so much for so detailed reply.

    I changed varchar to nvarchar for @sql and @due, it throws me more errors:

    Msg 102, Level 15, State 1, Line 1

    Incorrect syntax near 'due'.

    Msg 137, Level 15, State 2, Line 1

    Must declare the scalar variable "@Due".

  • If you don't mind, here is the sp, thank you very much.

    USE [Pergamum]

    GO

    /****** Object: StoredProcedure [dbo].[spGetDeviationReportNew2] Script Date: 11/06/2012 09:54:34 ******/

    SET ANSI_NULLS ON

    GO

    SET QUOTED_IDENTIFIER ON

    GO

    -- Stored Procedure

    ALTER PROCEDURE [dbo].[spGetDeviationReportNew2] (@ITSDivisionID int, @Due nvarchar(20))

    AS

    declare @OverDue nvarchar(20)

    declare @DueIn30Days nvarchar(255)

    declare @DueIn60Days nvarchar(255)

    declare @DueIn90Days nvarchar(255)

    declare @DueIn180Days nvarchar(255)

    set @OverDue = '999'

    set @DueIn30Days = '30'

    set @DueIn60Days = '60'

    set @DueIn90Days = '90'

    set @DueIn180Days = '180'

    declare @sql nvarchar(1000)

    set @sql = 'Select DocID, Code, Ref, Title, DocType, FileName, InitialSignOffDate, LastReviewDate, NextReviewDate, '+

    ' Due = Replace(@Due, ' + '''' + 'in' + '''' + ', ' + '''' + 'Within' + '''' + '), DueValue, SA, Type, Category, '+

    ' Division, ITSDivision, Contact, Phone) From ##temp where DueValue <= '

    if (@Due = 'All') set @sql = 'Select * From ##temp'

    if (@Due = 'OverDue') set @sql = @sql + @OverDue

    if (@Due = 'Due In 30 Days') set @sql = @sql + @DueIn30Days

    if (@Due = 'Due In 60 Days') set @sql = @sql + @DueIn60Days

    if (@Due = 'Due In 90 Days') set @sql = @sql + @DueIn90Days

    if (@Due = 'Due In 180 Days') set @sql = @sql + @DueIn180Days

    else

    Select ITSDivision = 'All', Due = @Due

    End

    ELSE

    --exec (@sql)

    EXEC sp_executeSQL @sql, @Due

    drop table ##temp

  • That's from the missing "list the parameters" piece that I mentioned. Look at the samples, you'll see how it goes.

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • Thank you, I will try to fix it myself

  • Try replacing this:

    EXEC sp_executeSQL @sql, @Due

    With:

    EXEC sp_executeSQL @sql, N'@Due NVARCHAR(20)', @Due

    See if that does what you need.

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • When your code reaches the statement

    if (@Due = 'All') set @sql = 'Select * From ##temp'

    It is realising that @due has not been declared. The '@due' in the string above it is not recognized as a variable

    ----------------------------------------------------

  • mmartin1 (11/7/2012)


    When your code reaches the statement

    if (@Due = 'All') set @sql = 'Select * From ##temp'

    It is realising that @due has not been declared. The '@due' in the string above it is not recognized as a variable

    @Due is declared as an input parameter in the usual manner for procs. It's in-scope at that stage of the code. Where it's not "declared" is inside the dynamic SQL string.

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • Ok thanks for the note, I missed that. I guess haste does make waste.

    ----------------------------------------------------

Viewing 13 posts - 1 through 12 (of 12 total)

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