SQL不等于&空值

时间:2009-03-12 00:14:02

标签: sql performance oracle

我们想写这个查询:

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,从性能角度来看,这不是一个很好的选择。

9 个答案:

答案 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

更新2

如果您的值永远不为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或空字符串。