我们想写这个查询:
select * from table
where col1 != 'blah' and col2 = 'something'
我们希望查询包含col1为null的行(而col2 ='something')。目前,查询不会对col1为null的行执行此操作。以下查询是最好和最快的方式吗?
select * from table
where (col1 != 'blah' or col1 is null) and col2 = 'something'
或者,如果需要,我们可以将所有col1 null值更新为空字符串。这会是一个更好的方法吗?然后我们的第一个查询就可以了。
更新:重新:使用NVL:我已经阅读了另一个post,从性能角度来看,这不是一个很好的选择。
答案 0 :(得分:16)
在Oracle中,空字符串与NULL之间没有区别。
这是公然无视SQL标准,但你去了......
除此之外,你不能用“普通”运算符比较NULL(或非NULL):“col1 = null”不起作用,“col1 =''”不起作用,“col1!= null”不会起作用,你必须使用“is null”。
所以,不,你不能以任何其他方式使这项工作,然后“col 1为null”或其中的一些变化(例如使用nvl)。
答案 1 :(得分:3)
我认为您发布的解决方案是最佳选择之一。
关于性能,在我看来这并不是一个很大的区别,如果子句已经有一个!=比较,通常优化器不会在该列中使用索引,因为选择性不够,所以更有区别的过滤器将是“和”条件的另一面。
如果你问我,我不会将空字符串用作null,但可能只是个人偏好。
答案 2 :(得分:3)
虽然不是最具可读性 - 但Oracle有LNNVL Function本质上是not()函数,但是反转了null的行为。意味着将lnnvl中的任何内容与null进行比较将返回true(我不知道它可能具有什么性能影响)。
在一个陈述中做你想做的事:
select * from table where lnnvl(col1 = 'blah') and col2 = 'something'
请注意,这仅适用于将可空值与可以保证不可为空的值进行比较。否则你需要像Thilo建议的那样 - 使用类似于
的运算符lnnvl(nvl(col1, -1) = nvl(col2, -1))
答案 3 :(得分:2)
这取决于你的数据,但是大多数优化器会在col1之前查看col2,因为=比索引更容易索引。=。
否则,您可以通过多种方式加快此查询速度。这可能是最好的(col1!='blah'或col1为null),但某些数据库允许您索引函数。因此,您可以索引coalesce(col1,0)并获得良好的性能。
真的取决于你的数据和你的桌子。
答案 4 :(得分:0)
在oracle中使用nvl函数
select * from table where nvl(col1,'notblah') <> 'blah'
答案 5 :(得分:0)
如果您希望加速此类查询,并且您使用的是Oracle 10g或更高版本,请使用基于函数的索引将这些NULL转换为值:
CREATE INDEX query_specific_index ON table (col2, NVL(col1,'***NULL***'));
select * from table
where NVL(col1,'***NULL***') != 'blah' and col2 = 'something';
数据库很可能在这种情况下使用索引(当然,根据CBO的决定,受行数和统计数据的准确性影响)。查询必须使用索引中给出的确切表达式 - 在本例中为“NVL(col1,'***NULL***')
”
当然,选择'***NULL***'
的值不会与col1中的任何数据冲突!
答案 6 :(得分:0)
这个选项怎么样?我认为如果你的价值永远无效,它可能会有效。
where not (value = column)
将导致以下真值表用于评估where子句
col1
| 'bla' | null |
-----------------
| 'bla' | F | T |
value -------------------------
| null | T | *T |
*这是唯一一个“错误”但是没关系,因为我们的值永远不会为空
好的,我刚试了一下我的想法而且失败了。我会在这里留下答案,以节省其他人尝试同样的事情的时间。以下是我的结果:
select 'x', 'x' from dual where not ('x' = 'x');
0 rows
select 'x', 'y' from dual where not ('x' = 'y');
1 row
select 'x', 'null' from dual where not ('x' = null);
0 rows
select 'null', 'null' from dual where not (null = null);
0 rows
如果您的值永远不为null(与上面的真值表相匹配)
,则此解决方案有效where ('blah' != col1 or col1 is null)
在这里测试:
select 'x', 'x' from dual where ('x' != 'x' or 'x' is null);
0 rows
select 'x', 'y' from dual where ('x' != 'y' or 'y' is null);
1 row
select 'x', 'null' from dual where ('x' != null or null is null);
1 row
select 'null', 'null' from dual where (null != null or null is null);
1 row
答案 7 :(得分:-1)
对于Oracle
select * from table where nvl(col1, 'value') != 'blah' and col2 = 'something'
对于SqlServer
select * from table where IsNull(col1, '') <> 'blah' and col2 = 'something'
答案 8 :(得分:-3)
我认为在将NULL值更改为“”字符串时,您的增加量会很小。但是,如果'blah'不为null,那么它应该包含NULL值。
编辑:我想我为什么在这里被投票感到惊讶。如果'blah'如果不为null或空字符串,则它应该永远不会重要,因为您已经在检查COL1是否不等于'blah',它不是NULL或空字符串。