Dynamic SQL Query Search

廉价感情. 提交于 2019-12-11 21:13:35

问题


I'm trying to build an SQL query with given params, but I get a weird error and cant understand why. Here is my SP and result

ALTER PROCEDURE [dbo].[sp_Photographers_Select_Search]
    @Date varchar(100),
    @PriceMin int,
    @PriceMax int,
    @CityID int

AS
BEGIN
    SET DATEFORMAT DMY
    DECLARE @SQL as varchar(2000)
    SET @SQL = 'SELECT *,
     (SELECT TOP (1) Price FROM  Packages WHERE PhotographerID = Photographers.PhotographerID ORDER BY Price) as PriceMin,
     (SELECT TOP (1) Price FROM  Packages WHERE PhotographerID = Photographers.PhotographerID ORDER BY Price DESC) as PriceMax,
     (SELECT COUNT(GalleryID) FROM Galleries WHERE PhotographerID = Photographers.PhotographerID AND Status = 1) as GalleryCount,
     (SELECT COUNT(CommentID) FROM Comments WHERE ContentID = Photographers.PhotographerID AND Status = 1 AND TypeID = 1) as CommentCount
     FROM Photographers WHERE 1 = 1  '

    IF @PriceMin <> 0 OR @PriceMax <> 0 BEGIN
        SET @SQL = @SQL + ' AND PhotographerID IN(SELECT PhotographerID FROM Packages WHERE Price BETWEEN '+@PriceMin+' AND '+@PriceMax+') '
    END

    IF @CityID > 0
        SET @SQL += ' AND CityID = '+@CityID+'' 

    SET @SQL = @SQL + ' AND  PhotographerID NOT IN (SELECT PhotographerID FROM Appointments WHERE Date = '''+@Date+''')'    

    EXEC (@SQL)
END

EXEC    @return_value = [dbo].[sp_Photographers_Select_Search]
        @Date = N'23.05.2013',
        @PriceMin = 0,
        @PriceMax = 0,
        @CityID = 34

And the error is

Msg 245, Level 16, State 1, Procedure sp_Photographers_Select_Search, Line 23
Conversion failed when converting the varchar value 'SELECT *,
     (SELECT TOP (1) Price FROM  Packages WHERE PhotographerID = Photographers.PhotographerID ORDER BY Price) as PriceMin,
     (SELECT TOP (1) Price FROM  Packages WHERE PhotographerID = Photographers.PhotographerID ORDER BY Price DESC) as PriceMax,
     (SELECT COUNT(GalleryID) FROM Galleries WHERE PhotographerID = Photographers.PhotographerID AND Status = 1) as GalleryCount,
     (SELECT COUNT(CommentID) FROM Comments WHERE ContentID = Photographers.PhotographerID AND Status = 1 AND TypeID = 1) as CommentCount
     FROM Photographers WHERE 1 = 1  ' to data type int.

Can you describe the error? Thanks!


回答1:


Cast the numeric values i.e. @PriceMin , @PriceMax and @CityID before concatenating in sql statement.

Modified sql statement is as per below:

IF @PriceMin <> 0 OR @PriceMax <> 0 
BEGIN
    SET @SQL = @SQL + ' AND PhotographerID IN(SELECT PhotographerID FROM Packages WHERE Price BETWEEN '+ cast(@PriceMin as varchar(10)) 
    +' AND '+ cast(@PriceMax as varchar(10)) +') '
END

IF @CityID > 0
   SET @SQL += ' AND CityID = '+ cast(@CityID as varchar(10) )



回答2:


Romil's answer solves the problem you asked, but what you should be asking is how to change this query to not be dynamic. I don't know your DB structure so this query will need to be verified but the WHERE clause updates I made will allow your query to run without being dynamic. This will increase performance dramatically, reduce injection exposure, and is all around the better way to go about these types of queries.

ALTER PROCEDURE [dbo].[sp_Photographers_Select_Search]
    @Date       AS VARCHAR(100),
    @PriceMin   AS INT,
    @PriceMax   AS INT,
    @CityID     AS INT

AS
BEGIN
    SET DATEFORMAT DMY
    SELECT  *,
            (SELECT TOP (1) Price FROM Packages WHERE PhotographerID = Photographers.PhotographerID ORDER BY Price) AS PriceMin,
            (SELECT TOP (1) Price FROM Packages WHERE PhotographerID = Photographers.PhotographerID ORDER BY Price DESC) AS PriceMax,
            (SELECT COUNT(GalleryID) FROM Galleries WHERE PhotographerID = Photographers.PhotographerID AND Status = 1) AS GalleryCount,
            (SELECT COUNT(CommentID) FROM Comments WHERE ContentID = Photographers.PhotographerID AND Status = 1 AND TypeID = 1) AS CommentCount
    FROM    Photographers
    WHERE   1 = 1
        AND PhotographerID NOT IN (SELECT PhotographerID FROM Appointments WHERE Date = @Date)
        AND 
        (
            (
                @PriceMin = 0
                AND @PriceMax = 0
            )
            OR  PhotographerID IN (SELECT PhotographerID FROM Packages WHERE Price BETWEEN @PriceMin AND @PriceMax)
        )
        AND 
        (
            @CityID = 0
            OR  CityID = @CityID
        )
END

I would make further improvements to move those sub-queries into JOIN statements combined with GROUP BY statements to improve performance, but that would require further DB knowledge.



来源:https://stackoverflow.com/questions/15067472/dynamic-sql-query-search

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!