简体   繁体   中英

How to pass in a string into dynamic sql inside a stored procedure

As of now I have a SQL statement like this:

SELECT 
    y.ID, y.STATUS, y.CONTROLID, y.TRCDE
FROM 
    YTDTRNI AS y 
LEFT JOIN 
    VND AS v ON y.COMNO = v.COMNO 
WHERE 
    TRCDE ='RC' 
ORDER BY 
    ID DESC

I am trying to use this query inside a stored procedure using dynamic SQL. So far, my stored procedure looks like this:

SET @query =  N'SELECT y.ID, y.STATUS, y.CONTROLID, y.TRCDE
                FROM YTDTRNI AS y LEFT JOIN VND AS v ON y.COMNO = v.COMNO 
                WHERE TRCDE = ' + @searchtrtype + ' 
                ORDER BY ' + @orderbycondition

The variables @searchtrtype and @orderbycondition are of type nvarchar .

I am using a ASP.NET/C# program to call the stored procedure. However, it breaks with an exception:

An expression of non boolean type in a context where a condition is expected near 'ORDER'

I think I am getting error because the string values are not properly concatenated or formatted in inside the @query variable.

Open to any advice.

EDIT: my stored procedure looks like this at the moment:

在此处输入图片说明

When I execute the stored procedure, it returns the result set that I want but it also shows an error message :

Must declare the scalar variable "@dsearchtrtype".

I tried declaring it inside the BEGIN body and declaring it as part of a parameter for the stored procedure but it still shows that same message.

Learn to use parameters with sp_executesql . You can do this for @searchtrtype , but not @orderbycondition :

SET @query =  N'
SELECT y.ID, y.STATUS,y.CONTROLID,y.TRCDE
FROM YTDTRNI y LEFT JOIN
     VND v
     ON y.COMNO = v.COMNO 
WHERE TRCDE = @searchtrtype 
ORDER BY @orderbycondition';

SET @query = REPLACE(@query, '@orderbycondition', @orderbycondition);

EXEC sp_executesql @query,
                   N'@searchtrtype NVARCHAR(255)',   -- or whatever the right type is
                   @searchtrtype=@searchtrtype;

You cannot pass in identifiers, only values, so this doesn't work for @orderbycondition .

You need to parametrise your SQL. Concatenating string for SQL is an awful idea; as it leaves you open to injection. The way you want to do it would be:

DECLARE @query nvarchar(MAX);
SET @query =  N'SELECT y.ID,' + NCHAR(10) + 
              N'       y.STATUS,' + NCHAR(10) + 
              N'       y.CONTROLID,' + NCHAR(10) + 
              N'       y.TRCDE' + NCHAR(10) + 
              N'FROM YTDTRNI AS y' + NCHAR(10) + 
              N'     LEFT JOIN VND AS v ON y.COMNO = v.COMNO ' + NCHAR(10) + 
              N'WHERE TRCDE = @dsearchtrtype' + NCHAR(10) + 
              N'ORDER BY ' + QUOTENAME(@orderbycondition) + N';';
PRINT @SQL;

EXEC sp_executesql @query, N'@dsearchtrtype nvarchar(100)', @dsearchtrtype = @searchtrtype;

This, however, probably isn't going to work, due to your variable @orderbycondition . I don't know, however, what type of value that has, however, if it's something like 'ID desc' , this it would become ORDER BY [ID desc]; .

If this assumption is correct, I would suggest using 2 variables; one for the sort column and one for the direction, and replace the final line of the dynamic SQl with:

N'ORDER BY ' + QUOTENAME(@orderbycolumn) + N' ' + CASE WHEN @orderbydirection NOT IN(N'ASC',N'DESC') THEN N'' ELSE @orderbydirection END + N';';

If your value of @orderbycondition can be more complex than that, post a comment to let me know (and update your question with more detail), and I'll be happy to explain how to create a more dynamic ORDER BY clause using a table type parameter, along with adding it to your dynamic SQL with use of STUFF and FOR XML PATH .

Based on the example provided it appears that the OP simply wants to filter on a single column and perform a sort on a user specified column. This can be achieved with a parametrized query without the need of dynamic SQL.

Within the where clause the TRCDE field can be directly assigned to the @searchtrtype parameter. The dynamic sorting requirement is a little trickier but can be achieved by using a CASE statement within the ORDER BY clause. An additional parameter will have to be included to indicate if the sorting should be ascending or descending. The following query demonstrates:

DECLARE @orderByColumn  NVARCHAR(50) = 'ID'; -- The column to sort by
DECLARE @sortAscending BIT = 1; -- Indicate sorting order 1 == Ascending, 0 == Descending
DECLARE @searchtrtype NVARCHAR(10) = 'RC'

IF @sortAscending = 1 -- Sort data in ascending order
BEGIN

    SELECT       y.[ID]
                ,y.[STATUS]
                ,y.[CONTROLID]
                ,y.[TRCDE]
    FROM        YTDTRNI AS y 
    LEFT JOIN   VND AS v ON y.[COMNO] = v.[COMNO]
    WHERE       TRCDE = @searchtrtype 
    ORDER BY    (
                    -- Create case statement for every column user may want to filter on
                    CASE
                        WHEN @orderByColumn = 'ID' THEN [ID]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ),
                 (
                    CASE
                        WHEN @orderByColumn = 'STATUS' THEN [STATUS]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ),
                             (
                    CASE
                        WHEN @orderByColumn = 'CONTROLID' THEN [CONTROLID]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ) ASC;
END
ELSE
BEGIN
    SELECT       y.[ID]
                ,y.[STATUS]
                ,y.[CONTROLID]
                ,y.[TRCDE]
    FROM        YTDTRNI AS y 
    LEFT JOIN   VND AS v ON y.[COMNO] = v.[COMNO]
    WHERE       TRCDE = @searchtrtype 
    ORDER BY    (
                    CASE
                        WHEN @orderByColumn = 'ID' THEN [ID]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ),
                 (
                    CASE
                        WHEN @orderByColumn = 'STATUS' THEN [STATUS]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ),
                             (
                    CASE
                        WHEN @orderByColumn = 'CONTROLID' THEN [CONTROLID]
                        ELSE NULL -- Simply return null if we are not ordering by this column, effectively ignore the column.
                    END
                 ) DESC;
END

This method is more work but will be easier to troubleshoot, maintain and will protect you from SQL Injection.

do you just need to include escaped apostrophes. if @searchtrtype can contain apostrophes, you might have to escape them with REPLACE(@searchtrtype, '''', '''''')

SET @query =  N'SELECT y.ID, y.STATUS,y.CONTROLID,y.TRCDE
FROM YTDTRNI AS y LEFT JOIN VND AS v ON y.COMNO = v.COMNO 
WHERE TRCDE = ''' + @searchtrtype + ''' 
ORDER BY ' + @orderbycondition

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM