SQL 嵌套的 IF-ELSE 语句
SQL Nested IF-ELSE Statements
好吧,我正式不知所措了。我正在尝试创建一个程序来运行每个后续检查并执行相应的查询。
但是,当我执行带有 one/two/all 个参数的过程时,它总是会陷入最终的 ELSE 并吐出 "cover-all" 结果集。为什么???
我怀疑可能是:
-If/Else语法
-括号的使用
-Begin/End个关键词
- IF 条件太多?
非常感谢任何帮助!
奖励积分:我可以在 WHERE 子句中使用搜索 CASE 来优化它吗?我知道我真的可以减少这段代码——但我真的很好奇为什么它不起作用。
CREATE PROC spBalanceRange
@VendorVar varchar(50) = NULL,
@BalanceMax money = NULL,
@BalanceMin money = NULL
AS
IF
(
@VendorVar != NULL
AND @BalanceMin != NULL
AND @BalanceMax != NULL
)
BEGIN
SELECT VendorName, InvoiceNumber, InvoiceTotal - (PaymentTotal + CreditTotal) AS BalanceDue
FROM Invoices JOIN Vendors
ON Invoices.VendorID = Vendors.VendorID
WHERE
VendorName = @VendorVar
AND InvoiceTotal - (PaymentTotal + CreditTotal) >= @BalanceMin
AND InvoiceTotal - (PaymentTotal + CreditTotal) <= @BalanceMax
END
ELSE IF
(
@VendorVar != NULL
AND @BalanceMin = NULL
AND
(
@BalanceMax = NULL
OR @BalanceMax = 0
)
)
BEGIN
SELECT VendorName, InvoiceNumber, InvoiceTotal - (PaymentTotal + CreditTotal) AS BalanceDue
FROM Invoices JOIN Vendors
ON Invoices.VendorID = Vendors.VendorID
WHERE
VendorName = @VendorVar
AND InvoiceTotal - (PaymentTotal + CreditTotal) > 0
END
ELSE
BEGIN
SELECT VendorName, InvoiceNumber, InvoiceTotal - (PaymentTotal + CreditTotal) AS BalanceDue
FROM Invoices JOIN Vendors
ON Invoices.VendorID = Vendors.VendorID
WHERE
InvoiceTotal - (PaymentTotal + CreditTotal) > 0
END
;
我认为这是因为您使用 ==
将它们与 null 进行比较。使用 t-sql 你总是需要使用 is
运算符。
尝试
x is not null
和
x is null
相反。
理想情况下,您应该使用动态 sql 来避免像这样的查询中的参数嗅探问题,动态 sql 的解决方案看起来像这样......
CREATE PROC spBalanceRange
@VendorVar varchar(50) = NULL,
@BalanceMax money = NULL,
@BalanceMin money = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Sql NVARCHAR(MAX);
SET @Sql = N'SELECT VendorName, InvoiceNumber, InvoiceTotal - (PaymentTotal + CreditTotal) AS BalanceDue
FROM Invoices
INNER JOIN Vendors ON Invoices.VendorID = Vendors.VendorID
WHERE '
+ CASE
WHEN (@VendorVar IS NOT NULL
AND @BalanceMin IS NOT NULL
AND @BalanceMax IS NOT NULL)
THEN N' VendorName = @VendorVar
AND InvoiceTotal - (PaymentTotal + CreditTotal) >= @BalanceMin
AND InvoiceTotal - (PaymentTotal + CreditTotal) <= @BalanceMax'
WHEN ( @VendorVar IS NOT NULL
AND @BalanceMin IS NULL
AND (@BalanceMax IS NULL OR @BalanceMax = 0))
THEN N' VendorName = @VendorVar
AND InvoiceTotal - (PaymentTotal + CreditTotal) > 0'
ELSE N' InvoiceTotal - (PaymentTotal + CreditTotal) > 0' END
Exec sp_executesql @Sql
,N'@VendorVar varchar(50),@BalanceMax money,@BalanceMin money'
,@VendorVar
,@BalanceMax
,@BalanceMin
END
我不在 windows 机器附近,所以这可能需要调整:
CREATE PROC spBalanceRange
@VendorVar varchar(50) = NULL,
@BalanceMax money = NULL,
@BalanceMin money = NULL
AS
SELECT VendorName, InvoiceNumber, InvoiceTotal - (PaymentTotal + CreditTotal) AS BalanceDue
FROM Invoices JOIN Vendors
ON Invoices.VendorID = Vendors.VendorID
WHERE
case when @VendorVar is null then true else vendorName=@vendorVar end
AND InvoiceTotal - (PaymentTotal + CreditTotal) >= coalesce(@BalanceMin,0)
AND case when @BalanceMax is null then true else InvoiceTotal - (PaymentTotal + CreditTotal) <= coalesce(@BalanceMax, 1e15) end;
另一种使用 case 语句的方法可能会显示您想要的结果:
CREATE PROCEDURE spBalanceRange
@VendorVar varchar(50) = NULL,
@BalanceMax money = NULL,
@BalanceMin money = NULL
AS
BEGIN
SELECT
b.VendorName, a.InvoiceNumber,
case
when InvoiceTotal - (PaymentTotal + CreditTotal) between @BalanceMax and @BalanceMin
then InvoiceTotal - (PaymentTotal + CreditTotal)
else 0
end BalanceDue
FROM Invoices a
JOIN Vendors b
ON a.VendorID = b.VendorID
WHERE
b.VendorName = @VendorVar
and InvoiceTotal - (PaymentTotal + CreditTotal) between @BalanceMax and @BalanceMin
END
希望我正确理解了您要完成的任务。
好吧,我正式不知所措了。我正在尝试创建一个程序来运行每个后续检查并执行相应的查询。
但是,当我执行带有 one/two/all 个参数的过程时,它总是会陷入最终的 ELSE 并吐出 "cover-all" 结果集。为什么???
我怀疑可能是: -If/Else语法 -括号的使用 -Begin/End个关键词 - IF 条件太多?
非常感谢任何帮助!
奖励积分:我可以在 WHERE 子句中使用搜索 CASE 来优化它吗?我知道我真的可以减少这段代码——但我真的很好奇为什么它不起作用。
CREATE PROC spBalanceRange
@VendorVar varchar(50) = NULL,
@BalanceMax money = NULL,
@BalanceMin money = NULL
AS
IF
(
@VendorVar != NULL
AND @BalanceMin != NULL
AND @BalanceMax != NULL
)
BEGIN
SELECT VendorName, InvoiceNumber, InvoiceTotal - (PaymentTotal + CreditTotal) AS BalanceDue
FROM Invoices JOIN Vendors
ON Invoices.VendorID = Vendors.VendorID
WHERE
VendorName = @VendorVar
AND InvoiceTotal - (PaymentTotal + CreditTotal) >= @BalanceMin
AND InvoiceTotal - (PaymentTotal + CreditTotal) <= @BalanceMax
END
ELSE IF
(
@VendorVar != NULL
AND @BalanceMin = NULL
AND
(
@BalanceMax = NULL
OR @BalanceMax = 0
)
)
BEGIN
SELECT VendorName, InvoiceNumber, InvoiceTotal - (PaymentTotal + CreditTotal) AS BalanceDue
FROM Invoices JOIN Vendors
ON Invoices.VendorID = Vendors.VendorID
WHERE
VendorName = @VendorVar
AND InvoiceTotal - (PaymentTotal + CreditTotal) > 0
END
ELSE
BEGIN
SELECT VendorName, InvoiceNumber, InvoiceTotal - (PaymentTotal + CreditTotal) AS BalanceDue
FROM Invoices JOIN Vendors
ON Invoices.VendorID = Vendors.VendorID
WHERE
InvoiceTotal - (PaymentTotal + CreditTotal) > 0
END
;
我认为这是因为您使用 ==
将它们与 null 进行比较。使用 t-sql 你总是需要使用 is
运算符。
尝试
x is not null
和
x is null
相反。
理想情况下,您应该使用动态 sql 来避免像这样的查询中的参数嗅探问题,动态 sql 的解决方案看起来像这样......
CREATE PROC spBalanceRange
@VendorVar varchar(50) = NULL,
@BalanceMax money = NULL,
@BalanceMin money = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Sql NVARCHAR(MAX);
SET @Sql = N'SELECT VendorName, InvoiceNumber, InvoiceTotal - (PaymentTotal + CreditTotal) AS BalanceDue
FROM Invoices
INNER JOIN Vendors ON Invoices.VendorID = Vendors.VendorID
WHERE '
+ CASE
WHEN (@VendorVar IS NOT NULL
AND @BalanceMin IS NOT NULL
AND @BalanceMax IS NOT NULL)
THEN N' VendorName = @VendorVar
AND InvoiceTotal - (PaymentTotal + CreditTotal) >= @BalanceMin
AND InvoiceTotal - (PaymentTotal + CreditTotal) <= @BalanceMax'
WHEN ( @VendorVar IS NOT NULL
AND @BalanceMin IS NULL
AND (@BalanceMax IS NULL OR @BalanceMax = 0))
THEN N' VendorName = @VendorVar
AND InvoiceTotal - (PaymentTotal + CreditTotal) > 0'
ELSE N' InvoiceTotal - (PaymentTotal + CreditTotal) > 0' END
Exec sp_executesql @Sql
,N'@VendorVar varchar(50),@BalanceMax money,@BalanceMin money'
,@VendorVar
,@BalanceMax
,@BalanceMin
END
我不在 windows 机器附近,所以这可能需要调整:
CREATE PROC spBalanceRange
@VendorVar varchar(50) = NULL,
@BalanceMax money = NULL,
@BalanceMin money = NULL
AS
SELECT VendorName, InvoiceNumber, InvoiceTotal - (PaymentTotal + CreditTotal) AS BalanceDue
FROM Invoices JOIN Vendors
ON Invoices.VendorID = Vendors.VendorID
WHERE
case when @VendorVar is null then true else vendorName=@vendorVar end
AND InvoiceTotal - (PaymentTotal + CreditTotal) >= coalesce(@BalanceMin,0)
AND case when @BalanceMax is null then true else InvoiceTotal - (PaymentTotal + CreditTotal) <= coalesce(@BalanceMax, 1e15) end;
另一种使用 case 语句的方法可能会显示您想要的结果:
CREATE PROCEDURE spBalanceRange
@VendorVar varchar(50) = NULL,
@BalanceMax money = NULL,
@BalanceMin money = NULL
AS
BEGIN
SELECT
b.VendorName, a.InvoiceNumber,
case
when InvoiceTotal - (PaymentTotal + CreditTotal) between @BalanceMax and @BalanceMin
then InvoiceTotal - (PaymentTotal + CreditTotal)
else 0
end BalanceDue
FROM Invoices a
JOIN Vendors b
ON a.VendorID = b.VendorID
WHERE
b.VendorName = @VendorVar
and InvoiceTotal - (PaymentTotal + CreditTotal) between @BalanceMax and @BalanceMin
END
希望我正确理解了您要完成的任务。