带 TVP 参数的条件 WHERE 子句
Conditional WHERE clauses with TVP parameter
我正在构建一个食谱网站,我正在尝试创建一个带有 table 值参数的存储过程,但是 运行 遇到了一些问题。
所以 TVP 是根据用户 select 在尝试搜索食谱时的复选框列表来填充的。然后我想展示基于这些 select 离子的配方,因此我在我的存储过程中使用了 TVP。
但是,当用户没有select 复选框列表之一中的任何选项时,我希望查询显示所有记录(对于每个部分)。当我尝试执行此操作时,查询立即 return 没有结果。
TVP 设置和逻辑
类别
难度[=65=]
持续时间
肉类
简单
0-15 分钟
string.Empty
平均
30-45 分钟
鱼
困难
string.Empty
我希望程序根据类别、难度和持续时间中的所有选项 select 过滤每个食谱。 IE。在这种情况下,我希望存储过程 return 所有具有 Category = "Meat" 或 "Fish" 的食谱;难度 =“简单”或“平均”或“困难”,持续时间 =“0-15 分钟”或“30-45 分钟”。
例如,如果类别中不存在任何值,则存储过程应该return 来自所有类别的食谱,并且仅根据具有值的列进行过滤。
到目前为止的工作代码
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
仅当我在所有三个复选框列表(称为类别、难度和持续时间)中 select 选项时,此代码才有效。
我试过的代码#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
None 这两次尝试都没有结果。你能帮我吗?我错过了什么?
谢谢!
我将提出类似以下的建议 - 尽管正如 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 table 中将没有行相应列中的值。 (如果这个假设不正确,那么我们将回到 Dale 的建议,即查看有关如何填充 @TVP 变量的更多详细信息 - 即您的应用程序端代码)
我正在构建一个食谱网站,我正在尝试创建一个带有 table 值参数的存储过程,但是 运行 遇到了一些问题。
所以 TVP 是根据用户 select 在尝试搜索食谱时的复选框列表来填充的。然后我想展示基于这些 select 离子的配方,因此我在我的存储过程中使用了 TVP。
但是,当用户没有select 复选框列表之一中的任何选项时,我希望查询显示所有记录(对于每个部分)。当我尝试执行此操作时,查询立即 return 没有结果。
TVP 设置和逻辑
类别 | 难度[=65=] | 持续时间 |
---|---|---|
肉类 | 简单 | 0-15 分钟 |
string.Empty | 平均 | 30-45 分钟 |
鱼 | 困难 | string.Empty |
我希望程序根据类别、难度和持续时间中的所有选项 select 过滤每个食谱。 IE。在这种情况下,我希望存储过程 return 所有具有 Category = "Meat" 或 "Fish" 的食谱;难度 =“简单”或“平均”或“困难”,持续时间 =“0-15 分钟”或“30-45 分钟”。
例如,如果类别中不存在任何值,则存储过程应该return 来自所有类别的食谱,并且仅根据具有值的列进行过滤。
到目前为止的工作代码
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
仅当我在所有三个复选框列表(称为类别、难度和持续时间)中 select 选项时,此代码才有效。
我试过的代码#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
None 这两次尝试都没有结果。你能帮我吗?我错过了什么?
谢谢!
我将提出类似以下的建议 - 尽管正如 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 table 中将没有行相应列中的值。 (如果这个假设不正确,那么我们将回到 Dale 的建议,即查看有关如何填充 @TVP 变量的更多详细信息 - 即您的应用程序端代码)