Problem in passing of parameters in a stored procedure. Please help.

  • Dear SQLCentral.com members and administrators,

    Hello guys, a greeting of peace.

    It is my first time here so I want to say sorry if in case this thread of mine is not in a proper discussion thread, because to be honest I am new to SQL Server and some technicalities are still broad to me, but I am trying my best to study more about Microsoft SQL server.

    I created a table named [font="Courier New"]Student[/font] and has four (4) fields: [font="Courier New"]id[/font], [font="Courier New"]fn[/font], [font="Courier New"]mi[/font], and [font="Courier New"]ln[/font] respectively (all are [font="Courier New"]NVARCHAR(20)[/font] type).

    I entered two (2) dummy data on my table, and here are the data:

    id fn mi ln

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

    001 PETER P PARKER

    002 ANTHONY A STARK

    I created a stored procedure named [font="Courier New"]SearchRecords[/font], this will be used in my C# program that will search for a data depending if he/she want to search by [font="Courier New"]id[/font], or by [font="Courier New"]fn[/font], or by [font="Courier New"]mi[/font], or by [font="Courier New"]ln[/font] . Here is the code of my stored procedure:

    CREATE PROCEDURE SearchRecords

    @searchQuery AS NVARCHAR(100),

    @col AS VARCHAR(100)

    AS

    BEGIN

    SET NOCOUNT ON;

    DECLARE @sql NVARCHAR(1000)

    DECLARE @value NVARCHAR(20)

    SET @value = @searchQuery

    IF (@col = 'PERSON_ID')

    BEGIN

    SET @sql = 'SELECT * FROM [Student] WHERE [id] = ' + @value

    END

    ELSE IF (@col = 'FIRST_NAME')

    BEGIN

    SET @sql = 'SELECT * FROM [Student] WHERE [fn] = ' + @value

    END

    EXEC (@SQL)

    END

    I tried to execute my stored procedure to check if it's working before I use it in my code in C#.

    I execute this in a stored procedure using a new query:

    EXEC SearchRecords '001','id'

    I get this result (which is good):

    id fn mi ln

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

    001 PETER P PARKER

    But when I try to change my seary query, like I want to search for a first name 'ANTHONY':

    EXEC SearchRecords 'ANTHONY','fn'

    I get this result:

    [font="Courier New"]Invalid column name 'ANTHONY'.[/font]

    I tried to change the data types, arrangement of variables, but still the same.

    I know it is very poorly constructed stored procedure, that is why I am asking some help what revision/s should I make in order to this stored procedure much flexible, becasue I do not want to create four (4) stored procedures for searching on each field.

    Thank you in advance and more power.

    Warm regards,

    Mark Squall 🙂

    ________________________________
    "Listen to advice and accept instruction, and in the end you will be wise." -Proverbs 19:20

  • There is absolutely no need for dynamic SQL here (and the problem was that there were no quotes around the concatenated string in the dynamic SQL.

    CREATE PROCEDURE SearchRecords

    @searchQuery AS NVARCHAR(100),

    @col AS VARCHAR(100)

    AS

    BEGIN

    SET NOCOUNT ON;

    IF (@col = 'PERSON_ID')

    SELECT * FROM [Student] WHERE [PERSON_ID] = @searchQuery

    IF (@col = 'FIRST_NAME')

    SELECT * FROM [Student] WHERE [FIRST_NAME] = @searchQuery

    END

    Edit: fixed parameters.

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • The first query works (when you correct the columns to match the parameters) because you're getting implicit type conversions to numbers. '001' becomes 1 on both sides of the equals statement.

    The second query errors because you can't convert ANTHONY to an integer.

    This stored procedure is rife with injection possibilities.

    Read either or both of these articles on a better way to do this.

    http://www.sommarskog.se/dyn-search-2005.html

    http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/

    The methodologies done here are applicable to this kind of query.



    --Mark Tassin
    MCITP - SQL Server DBA
    Proud member of the Anti-RBAR alliance.
    For help with Performance click this link[/url]
    For tips on how to post your problems[/url]

  • GilaMonster (4/10/2012)


    There is absolutely no need for dynamic SQL here (and the problem was that there were no quotes around the concatenated string in the dynamic SQL.

    Really? Wow... I recall a time when if you had two queries like this nested inside of IF statements

    (granted this is a really simple one) that the compiler would lose its mind.

    Then again I was probably working with more complicated queries at the time... 🙂



    --Mark Tassin
    MCITP - SQL Server DBA
    Proud member of the Anti-RBAR alliance.
    For help with Performance click this link[/url]
    For tips on how to post your problems[/url]

  • That said, this is a bad approach for a number of reasons and you should consider multiple procedures.

    This is just one reason:

    http://sqlinthewild.co.za/index.php/2009/09/15/multiple-execution-paths/

    Another reason has to do with the 'single responsibility' principal. You wouldn't write a C# class that could do one of several different things depending on a parameter passed to the constructor, similarly you shouldn't do that in T-SQL.

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • GilaMonster (4/10/2012)


    That said, this is a bad approach for a number of reasons and you should consider multiple procedures.

    This is just one reason:

    http://sqlinthewild.co.za/index.php/2009/09/15/multiple-execution-paths/

    Another reason has to do with the 'single responsibility' principal. You wouldn't write a C# class that could do one of several different things depending on a parameter passed to the constructor, similarly you shouldn't do that in T-SQL.

    Well technically isn't this just a varianet on the catch-all?

    My statement about losing its mind was actually in reference to your article above (something I knew about but you do such a better job writing about).



    --Mark Tassin
    MCITP - SQL Server DBA
    Proud member of the Anti-RBAR alliance.
    For help with Performance click this link[/url]
    For tips on how to post your problems[/url]

  • mtassin (4/10/2012)


    Really? Wow... I recall a time when if you had two queries like this nested inside of IF statements

    (granted this is a really simple one) that the compiler would lose its mind.

    See the link I just posted. The solution however is not dynamic SQL usually. It's multiple procedures.

    p.s. The reason the OP's code broke was not implicit conversions, the first_name column is nvarchar. It broke because the dynamic SQL would have been this at the point the query was executed

    SELECT * FROM [Student] WHERE [FIRST_NAME] = ANTHONY

    No quotes for the string value means that what was intended as a string literal would have been interpreted as a column name.

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • GilaMonster (4/10/2012)


    mtassin (4/10/2012)


    Really? Wow... I recall a time when if you had two queries like this nested inside of IF statements

    (granted this is a really simple one) that the compiler would lose its mind.

    See the link I just posted. The solution however is not dynamic SQL usually. It's multiple procedures.

    p.s. The reason the OP's code broke was not implicit conversions, the first_name column is nvarchar. It broke because the dynamic SQL would have been this at the point the query was executed

    SELECT * FROM [Student] WHERE [FIRST_NAME] = ANTHONY

    No quotes for the string value means that what was intended as a string literal would have been interpreted as a column name.

    Right... though again it's lack of caffeine here...

    The other one turned into

    SELECT * FROM [Student] WHERE [ID] = 001

    Which would get converted because he went dynamic... no?

    The second one couldn't do that... I should have been more clear... for the reason you stated above.



    --Mark Tassin
    MCITP - SQL Server DBA
    Proud member of the Anti-RBAR alliance.
    For help with Performance click this link[/url]
    For tips on how to post your problems[/url]

  • mtassin (4/10/2012)


    The other one turned into

    SELECT * FROM [Student] WHERE [ID] = 001

    Which would get converted because he went dynamic... no?

    That would be an implicit conversion whether the query is dynamic or not. 001 is numeric (no quotes), so the column gets converted to a matching numeric type (integer in this case)

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • Right... but if it hadn't been dynamic it would likely have been

    SELECT * FROM [Student] WHERE [PERSON_ID] = @value

    Which wouldn't have gone implicit. Because he chose to use dynamic SQL it went implicit because the appending of the variable onto the end of the query made it so.

    Which is what I was trying to say when I explained why execution 1 worked, and why execution 2 didn't..

    1 worked because 001 was implicitly converted to a number and so the column was also implicitly converted into a number.

    2 didn't work because the word ANTHONY couldn't be converted into anything and instead was treated as if it was a column.



    --Mark Tassin
    MCITP - SQL Server DBA
    Proud member of the Anti-RBAR alliance.
    For help with Performance click this link[/url]
    For tips on how to post your problems[/url]

  • Dear Ms. Gail Shaw and Sir Mark Tassin,

    Hello, thank you for the information and the links you have given to me. I will read them for another added knowledge on my part. Thank you because now I know I am creating a dynamic SQL (I am really sorry I did not knew what it is called). 😉

    To Ms. Gail Shaw:

    Actually Mam, that is my first plan, to create four (4) stored procedures for each search categories(i.e. search by [font="Courier New"]id[/font], search by [font="Courier New"]fn[/font], etc). Your link was useful. I just thought having four (4) different stored procedures that do the same thing (searching that is) will be considered as a bad practice.

    To Ms. Gail Shaw and Sir Mark Tassin:

    Does using sub stored procedure than dynamic SQL makes me less of an SQL programmer? Or is it the way around? Or any strategies will do as long as I achieve my goal? I am asking this because I do not know what would be the best practice and what are the standards used in the industry regarding my problem.

    Thank you, thank you for all the members that keeps on giving me new ideas. And more power.

    Warm regards,

    MarkSquall

    ________________________________
    "Listen to advice and accept instruction, and in the end you will be wise." -Proverbs 19:20

  • Dynamic SQL should be used when there's no other way of solving the problem. It's not the first thing you should think of. Also, a 'good SQL programmer' (whatever that means) should use the simplest, easiest solutions, not look for 'clever' or complex ways.

    p.s. I am not a Sir.

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • The correct answer, as always is... it depends.

    If you choose to use Dynamic SQL, then you need to be warey of injection.

    Creating a dynamic SQL string by appending text type variables onto it, especially those that come from parameters opens you up to injection.

    Using EXEC(@variable) instead of EXEC sp_executesql @varaible is also poor form

    Personally I have nothing against Dynamic SQL... So long as it's used responsibly.

    for instance, based on your stored proc.... what if I passed

    ;DELETE Student

    in as the value for @searchQuery ?

    Your query would turn into

    SELECT * FROM [Student] WHERE [ID] = ;DELETE Student

    OR

    SELECT * FROM [Student] WHERE [FN] = ;DELETE Student

    Which would probably not be what you wanted.



    --Mark Tassin
    MCITP - SQL Server DBA
    Proud member of the Anti-RBAR alliance.
    For help with Performance click this link[/url]
    For tips on how to post your problems[/url]

  • mtassin (4/10/2012)


    The correct answer, as always is... it depends.

    If you choose to use Dynamic SQL, then you need to be warey of injection.

    Creating a dynamic SQL string by appending text type variables onto it, especially those that come from parameters opens you up to injection.

    Using EXEC(@variable) instead of EXEC sp_executesql @varaible is also poor form

    Personally I have nothing against Dynamic SQL... So long as it's used responsibly.

    for instance, based on your stored proc.... what if I passed

    ;DELETE Student

    in as the value for @searchQuery ?

    Your query would turn into

    SELECT * FROM [Student] WHERE [ID] = ;DELETE Student

    OR

    SELECT * FROM [Student] WHERE [FN] = ;DELETE Student

    Which would probably not be what you wanted.

    Problems with dynamic SQL are not only limited to SQL Injection (although that is a big one). You also are looking at possibly filling your plan cache with junk if you have 30/300/3000 variations on a query based on changing values, parameters, etc. You're also hitting the CPU, requiring more compiles. You're getting less plan reuse. You have more opportunities for poorly written queries. You have a tougher time identifying and tuning queries.

    I'm sure I can come up with more reasons if I thought about it some more. I agree, there's nothing wrong with dynamic SQL, used in the appropriate places at appropriate times as long as it's well written, preferably using sp_executesql and paramters to help avoid SQL Injection and promote more, and better, plan reuse. But just a blanket statement saying "Yeah, it's fine, have fun, avoid injection" is a little dangerous to communicate, especially to someone just getting started.

    "The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
    - Theodore Roosevelt

    Author of:
    SQL Server Execution Plans
    SQL Server Query Performance Tuning

  • Ok Grant, so now I can learn...

    If he wrote it as

    ALTER PROCEDURE [dbo].[SearchRecords]

    @searchQuery AS NVARCHAR(100),

    @col AS VARCHAR(100)

    AS

    BEGIN

    SET NOCOUNT ON;

    DECLARE @sql NVARCHAR(1000)

    DECLARE @value NVARCHAR(20)

    SET @value = @searchQuery

    IF (@col = 'PERSON_ID')

    BEGIN

    SET @sql = 'SELECT * FROM [Student] WHERE [ID] = @value'

    END

    ELSE IF (@col = 'FIRST_NAME')

    BEGIN

    SET @sql = 'SELECT * FROM [Student] WHERE [FN] = @value'

    END

    EXEC sp_executesql @sql,N'@value nvarchar(20)',@value=@value

    END

    Yes there's a CPU penalty to pay, but wouldn't it wind up with just three plans in the cache? The original one that builds the query plus one for branch one, one for branch two and the parameter passed in would just be peachy?

    I don't understand how we get that many more plans into the cache by doing this or by creating two separate procedures and then executing them both. Seems I get two plans in the cache by creating two procs, and 3 if we go dynamic (one for the proc that builds the dynamic code, and one for each path of the code itself).

    I'm sure I'm missing something, which is why I tend to be more quiet around here and just read what you, Gail and Jeff tell me, but I thought I understood this one (more or less, though I did flub my terminology).



    --Mark Tassin
    MCITP - SQL Server DBA
    Proud member of the Anti-RBAR alliance.
    For help with Performance click this link[/url]
    For tips on how to post your problems[/url]

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

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