简体   繁体   English

带有 TVP 参数的条件 WHERE 子句

[英]Conditional WHERE clauses with TVP parameter

I am building a recipe website and I am trying to create a stored procedure with a table-valued parameter but am running into some issues.我正在构建一个食谱网站,我正在尝试使用表值参数创建一个存储过程,但遇到了一些问题。

So the TVP is filled based on the checkboxlists that the user selects when he is trying to search for a recipe.因此,TVP 是根据用户在尝试搜索食谱时选择的复选框列表填充的。 I then would like to show recipes based on those selections, and for that reason I used a TVP in my stored procedure.然后我想根据这些选择显示食谱,因此我在存储过程中使用了 TVP。

However I would like for the query to display all records (for each section) when the user does not select any options in one of the checkboxlists.但是,当用户在其中一个复选框列表中没有 select 任何选项时,我希望查询显示所有记录(每个部分)。 When I try to do this the query immediately returns no results.当我尝试这样做时,查询立即不返回任何结果。

TVP Setup and Logic TVP 设置和逻辑

Category类别 Difficulty困难 Duration期间
Meat Easy简单的 0-15 min 0-15分钟
string.Empty字符串.空 Average平均 30-45 min 30-45 分钟
Fish Hard难的 string.Empty字符串.空

I want the procedure to filter each recipe by all the options selected in Category, Difficulty and Duration.我希望该程序通过类别、难度和持续时间中选择的所有选项来过滤每个食谱。 Ie in this case, I want the stored procedure to return all recipes that have Category = "Meat" or "Fish";即在这种情况下,我希望存储过程返回具有 Category = "Meat" 或 "Fish" 的所有食谱; that have Difficulty = "Easy" or "Average" or "Hard" and have Duration = "0-15min" or "30-45min".难度 =“简单”或“平均”或“困难”并且持续时间 =“0-15 分钟”或“30-45 分钟”。

In case no values exist in Category, for instance, the stored procedure should return recipes from all categories, and only filter based on the columns that have values.例如,如果 Category 中不存在值,则存储过程应返回所有类别的食谱,并且仅根据具有值的列进行过滤。

Working code so far到目前为止的工作代码

ALTER PROCEDURE uspPesquisarReceita (@TVP dbo.Filters READONLY)
AS
BEGIN
    SELECT R.RecipeName, C.Category, DF.Dificulty, D.Duration, R.Rating, R.Publication, R.Photo, R.Views, R.IDRecipe
        FROM dbo.Recipes R 
        LEFT JOIN dbo.Categories C ON R.IDCategory = C.IDCategory 
        LEFT JOIN dbo.Dificulty DF ON R.IDDificulty = DF.IDDificulty
        LEFT JOIN dbo.Duration D ON R.IDDuration = D.IDDuration
        WHERE R.IDStatus = 1 
        AND (C.Category IN (SELECT Category FROM @TVP)
        AND DF.Dificulty IN (SELECT Dificulty FROM @TVP) 
        AND D.Duration IN (SELECT Duration FROM @TVP))
END

This code is working, only when I select options in all three of the checkboxlists (called Category, Dificulty and Duration).只有当我在所有三个复选框列表(称为类别、难度和持续时间)中选择 select 时,此代码才有效。

Code I have tried #1我尝试过的代码#1

ALTER PROCEDURE uspPesquisarReceita (@TVP dbo.Filters READONLY)
    AS
    BEGIN
        SELECT R.RecipeName, C.Category, DF.Dificulty, D.Duration, R.Rating, R.Publication, R.Photo, R.Views, R.IDRecipe
            FROM dbo.Recipes R 
            LEFT JOIN dbo.Categories C ON R.IDCategory = C.IDCategory 
            LEFT JOIN dbo.Dificulty DF ON R.IDDificulty = DF.IDDificulty
            LEFT JOIN dbo.Duration D ON R.IDDuration = D.IDDuration
            WHERE R.IDStatus = 1 
            AND (C.Category IN (CASE WHEN NOT EXISTS (SELECT Category FROM @TVP)
                                 THEN
                                  (SELECT R.RecipeName, C.Category, DF.Dificulty, D.Duration, 
                                  R.Rating, R.Publication, R.Photo, R.Views, R.IDRecipe
                                  FROM dbo.Recipes R 
                                  LEFT JOIN dbo.Categories C ON R.IDCategory = C.IDCategory 
                                  LEFT JOIN dbo.Dificulty DF ON R.IDDificulty = DF.IDDificulty
                                  LEFT JOIN dbo.Duration D ON R.IDDuration = D.IDDuration
                                  WHERE R.IDStatus = 1)
                                 ELSE (SELECT Category FROM @TVP) 
            AND DF.Dificulty IN (SELECT Dificulty FROM @TVP)
                                  *same as above*
            AND D.Duration IN (SELECT Duration FROM @TVP))
                                  *same as above*
    END

Code I have tried #2 (only with example for Category)我尝试过的代码#2 (仅以类别为例)

ALTER PROCEDURE uspPesquisarReceita (@TVP dbo.Filters READONLY)
        AS
        BEGIN
            IF NOT EXISTS (SELECT Category FROM @TVP)
                SELECT R.RecipeName, C.Category, DF.Dificulty, D.Duration, R.Rating, 
                R.Publication, R.Photo, R.Views, R.IDRecipe
                FROM dbo.Recipes R 
                LEFT JOIN dbo.Categories C ON R.IDCategory = C.IDCategory 
                LEFT JOIN dbo.Dificulty DF ON R.IDDificulty = DF.IDDificulty
                LEFT JOIN dbo.Duration D ON R.IDDuration = D.IDDuration
                WHERE R.IDStatus = 1
                AND DF.Dificulty IN (SELECT Dificulty FROM @TVP) 
                AND D.Duration IN (SELECT Duration FROM @TVP))
            ELSE
                SELECT R.RecipeName, C.Category, DF.Dificulty, D.Duration, R.Rating, 
                R.Publication, R.Photo, R.Views, R.IDRecipe
                FROM dbo.Recipes R 
                LEFT JOIN dbo.Categories C ON R.IDCategory = C.IDCategory 
                LEFT JOIN dbo.Dificulty DF ON R.IDDificulty = DF.IDDificulty
                LEFT JOIN dbo.Duration D ON R.IDDuration = D.IDDuration
                WHERE R.IDStatus = 1 
                AND (C.Category IN (SELECT Category FROM @TVP)
                AND DF.Dificulty IN (SELECT Dificulty FROM @TVP) 
                AND D.Duration IN (SELECT Duration FROM @TVP))
    END

None of these two attempts have yielded any results.这两次尝试都没有产生任何结果。 Can you help me out?你能帮我吗? What am I missing?我错过了什么?

Thank you!谢谢!

I'm going to suggest something like the following - although, as Dale points out, it would be kind of handy to see exactly how your @TVP value looks when it's populated with different combinations of filters.我将建议如下内容 - 尽管正如 Dale 指出的那样,当您的 @TVP 值填充了不同的过滤器组合时,它会很方便地查看它的外观。 However, in the interim, give this a try and see what results you get.但是,在此期间,请尝试一下,看看您会得到什么结果。

ALTER PROCEDURE uspPesquisarReceita (@TVP dbo.Filters READONLY)
AS
BEGIN
    SELECT R.RecipeName, C.Category, DF.Dificulty, D.Duration, R.Rating, R.Publication, R.Photo, R.Views, R.IDRecipe
        FROM dbo.Recipes R 
        LEFT JOIN dbo.Categories C ON R.IDCategory = C.IDCategory 
        LEFT JOIN dbo.Dificulty DF ON R.IDDificulty = DF.IDDificulty
        LEFT JOIN dbo.Duration D ON R.IDDuration = D.IDDuration
        WHERE R.IDStatus = 1 
        AND
        (
            (C.Category IN (SELECT Category FROM @TVP))
            OR
            (NOT EXISTS (SELECT 1 FROM @TVP WHERE LTRIM(ISNULL(Category, '')) <> ''))
        )
        AND 
        (
            (DF.Dificulty IN (SELECT Dificulty FROM @TVP))
            OR
            (NOT EXISTS (SELECT 1 FROM @TVP WHERE LTRIM(ISNULL(Dificulty, '')) <> ''))
        )
        AND 
        (
            (D.Duration IN (SELECT Duration FROM @TVP))
            OR
            (NOT EXISTS (SELECT 1 FROM @TVP WHERE LTRIM(ISNULL(Duration, '')) <> ''))
        )
END

Basically, I'm assuming that if a user hasn't ticked any options for a particular filter (Category, Difficulty or Duration), then there will be no rows in the @TVP table with a value in the corresponding column.基本上,我假设如果用户没有为特定过滤器(类别、难度或持续时间)勾选任何选项,那么@TVP 表中将没有相应列中具有值的行。 (If this assumption is incorrect, then we are back to Dale's suggestion of seeing more detail on how you are populating the @TVP variable - ie. your app-side code) (如果这个假设不正确,那么我们将回到 Dale 的建议,即查看有关您如何填充 @TVP 变量的更多详细信息 - 即您的应用程序端代码)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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