带 TVP 参数的条件 WHERE 子句

时间:2021-06-06 22:47:46

标签: sql sql-server tsql stored-procedures

我正在构建一个食谱网站,我正在尝试创建一个带有表值参数的存储过程,但遇到了一些问题。

因此,TVP 是根据用户在尝试搜索食谱时选择的复选框列表来填充的。然后我想根据这些选择显示食谱,因此我在存储过程中使用了 TVP。

但是,当用户未在复选框列表之一中选择任何选项时,我希望查询显示所有记录(对于每个部分)。当我尝试执行此操作时,查询立即不返回任何结果。

TVP 设置和逻辑

<头>
类别 难度 持续时间
简单 0-15 分钟
string.Empty 平均 30-45 分钟
string.Empty

我希望程序通过在类别、难度和持续时间中选择的所有选项过滤每个食谱。 IE。在这种情况下,我希望存储过程返回所有具有 Category = "Meat" 或 "Fish" 的食谱;难度 =“简单”或“平均”或“难”,持续时间 =“0-15 分钟”或“30-45 分钟”。

例如,如果 Category 中不存在任何值,则存储过程应返回所有类别的配方,并且仅根据具有值的列进行过滤。

目前的工作代码

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

此代码有效,仅当我在所有三个复选框列表(称为类别、难度和持续时间)中选择选项时。

我尝试过的代码 #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

我尝试过的代码#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

这两次尝试都没有产生任何结果。你能帮我吗?我错过了什么?

谢谢!

1 个答案:

答案 0 :(得分:0)

我将建议类似以下内容 - 尽管正如 Dale 所指出的那样,当 @TVP 值填充不同的过滤器组合时,查看它的确切外观会很方便。但是,在此期间,请尝试一下,看看会得到什么结果。

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

基本上,我假设如果用户没有勾选特定过滤器的任何选项(类别、难度或持续时间),那么@TVP 表中将不会有相应列中有值的行。 (如果此假设不正确,那么我们将回到 Dale 的建议,即查看有关如何填充 @TVP 变量的更多详细信息 - 即您的应用程序端代码)

相关问题