我有一份SSRS报告,其中有一个参数要求用户包含收入大于零的记录,或者收入值仅为零的记录。
由于查询不是存储过程,并且不能将其放入过程中,因此我需要为嵌入式查询使用一些案例逻辑。我最后需要在where子句中执行此操作。
我正在尝试做这样的事情:
SELECT * FROM TABLE
WHERE MY_DATE BETWEEN D_START AND D_END
AND
CASE
WHEN :REVENUE = 1 THEN REV != 0
WHEN :REVENUE = 2 THEN REV = 0
END
但是,当我运行此查询时,我收到以下错误:
ORA-00905: missing keyword
我做的不可能吗?或者是否有人可以看到并帮助我的错误?
请帮忙。谢谢!
更新:为了澄清,用户传递的值为1或2.查询应根据传递给它的值过滤数据。如果参数中传递了1,则过滤掉所有不等于零的收入。否则,如果两个传递,则过滤,以便仅返回收入为零的记录。
答案 0 :(得分:2)
您可以使用一些布尔逻辑更好地编写它:
SELECT * FROM TABLE
WHERE MY_DATE BETWEEN D_START AND D_END
AND (
(:REVENUE = 1 AND REV != 0)
OR
(:REVENUE = 2 AND REV = 0 )
)
CASE用于根据条件提取不同的值,因此您可以使用它来检查条件,但您需要将其用作检查条件的值
答案 1 :(得分:2)
没有必要使用CASE
表达式来获得此特定结果。
但是可以使用一个。
原始查询中的问题是Oracle比其他数据库(如MySQL)更严格,因为Oracle没有隐式地将布尔表达式转换为值,或将值转换为 boolean 。
我怀疑甲骨文在几个地方窒息。错误消息只向我们展示了其中一个。
CASE表达式返回值,而甲骨文则不愿意将值作为布尔值进行评估。
要将该值评估为布尔值,我们可以将值的比较与其他值进行比较。
如果我们解决这个问题,我认为甲骨文仍然会在THEN
之后扼杀表达式。 Oracle希望返回一个值,并且它会找到一个比较,它会计算为布尔值。
好的,我们知道CASE
表达式需要返回一个值,我们需要在布尔表达式中使用它。如果我们将条件测试移到WHEN
部分,并指定要在THEN
中返回的值,我们可以将CASE表达式的返回值与另一个值进行比较。
(顺便说一句......我强烈建议您在SQL语句中限定列引用。这使得意图更加清晰。查看语句,看起来MY_DATE,D_START和D_END都是列引用。 #39;完全有效,对我来说似乎有点奇怪。)
例如,我们可以使用CASE
表达式执行类似的操作:
SELECT t.*
FROM TABLE t
WHERE t.MY_DATE BETWEEN t.D_START AND t.D_END
AND CASE
WHEN ( :REVENUE = 1 AND t.REV != 0 ) THEN 1
WHEN ( :REVENUE = 2 AND t.REV = 0 ) THEN 1
ELSE NULL
END = 1
CASE中的parens是不必要的;我只是将它们包含在内以突出显示Oracle在布尔上下文中评估的部分。
那么,这有用吗?如果传入的值为:REVENUE为2,则第一个WHEN中的条件不会评估为TRUE(第一次比较的结果保证为FALSE)。第二个WHEN中的条件可以评估为TRUE(第一个比较将产生TRUE,第二个比较的结果将取决于REV
列中的值。)
该CASE表达式将返回值1或NULL。 (如果需要,我们可以很容易地使用0或-1或999代替NULL。)
评估CASE表达式后,返回的值将与文字值进行比较,就像我们写的那样val = 1
。该比较被评估为布尔值。如果它的计算结果为TRUE,则返回行...
为了使Oracle的行为与其他数据库(如MySQL)类似,我们需要将布尔值转换为值,将值转换为布尔显式。我们仍然需要CASE的回报与1相比,就像我们上面所做的那样。代替REV != 0
我们可以使用另一个CASE表达式。我不推荐这个,只是在这里显示,将布尔转换为值。
WHERE CASE
WHEN ( :REVENUE = 1 )
THEN CASE WHEN ( t.REV != 0 ) THEN 1 ELSE NULL END
WHEN ( :REVENUE = 2 )
THEN CASE WHEN ( t.REV = 0 ) THEN 1 ELSE NULL END
ELSE
NULL
END = 1
请注意,最外层CASE表达式的返回值与一个值进行比较,因此我们得到一个布尔值(Oracle期望一个布尔值。)
上述语句中的所有ELSE NULL
都可以省略等效结果,因为省略ELSE
时默认为{。}}。
同样,没有必要使用CASE
表达式。没有它你可以获得相同的结果。例如:
SELECT t.*
FROM TABLE t
WHERE t.MY_DATE BETWEEN t.D_START AND t.D_END
AND ( ( :REVENUE = 1 AND t.REV != 0 )
OR ( :REVENUE = 2 AND t.REV = 0 )
)
在这些都返回等效结果的查询中,CASE
表达式并不能为我们买任何东西。但在某些情况下,它可以比常规OR
具有一些优势,因为当CASE
子句中的条件求值为WHEN
时,TRUE
表达式会停止求值。
答案 2 :(得分:0)
问题是Oracle SQL没有布尔数据类型,所以你不能拥有boolean类型的列,将boolean参数传递给查询,有布尔表达式等等。所以他们有一些不自然的概念"条件"这是进入逻辑条件的东西(比如在WHERE子句中)。不幸的是,当他们引入案例EXPRESSION时,可以在任何其他表达式可以使用的地方使用(但是这不包括布尔值),它们不会引入一个" case CONDITION" - 可以在可以使用其他条件的情况下使用。这种遗漏很奇怪,因为案例条件的代码可能会使用95%的代码用于case表达式。更加奇怪,因为PL / SQL确实具有布尔类型,并且案例表达式可以无缝地用于布尔值。