【问题标题】:Selecting Rows with one column or Columns with NULL value when even one have value选择具有一列的行或具有 NULL 值的列,即使一列具有值
【发布时间】:2019-10-14 13:57:45
【问题描述】:

我有一个表,我想在其中选择一行,即使第 1 列和第 4 列中的任何一个具有 NOT NULL 值,而另一个在 ORACLE 中具有 NULL 值

如果我的数据如下所示

          col1    col2    col3    col4
row1      1       null    null    null
row2      null    2       null    null
row3      null    null    3       null
row4      null    null    null    level1
row5      11      22      33      level2
row6      11      null    33      level2
row7      null    null    null    null

我期待如下输出

          col1    col2    col3    col4
row1      1       null    null    null
row2      null    2       null    null
row3      null    null    3       null
row4      null    null    null    level1
row6      11      null    33      level2

我有一个非常大的表,我在这些列上都没有索引,有点担心使用类似下面的查询。

select * from table_name 
   where col1 <> null and col2 = null and col3 = null and col4 = null
   or col1 = null and col2 <> null and col3 = null and col4 = null
    ...

在ORACLE sql中有没有更好的写法?

【问题讨论】:

  • 您的行是否有某种id 列?

标签: sql oracle oracle11g


【解决方案1】:

您可以在此处使用GREATESTLEAST 函数:

SELECT *
FROM yourTable
WHERE GREATEST(col1, col2, col3, col4) IS NULL;

如果四列中的至少一列具有NULL 值,则上述对GREATEST 的调用只会是NULL

如果您还想确保给定行至少有一个非NULL 值,则将其添加到WHERE 子句的条件:

SELECT *
FROM yourTable
WHERE
    GREATEST(col1, col2, col3, col4) IS NULL AND
    COALESCE(col1, col2, col3, col4) IS NOT NULL;

【讨论】:

  • 但是如果所有字段都为空,这也将返回空,如果我没记错的话,这不是 OP 所问的
  • @vc74 我为此添加了一个条件,如果 OP 也有这个要求。
  • 感谢@TimBiegeleisen 这有效,这就是我想要的。再次感谢!
  • 我仍然不清楚只有空行会发生什么,但因为他/她接受了你的回答......
  • @vc74 如果所有列都为 NULL 则可以忽略,我已更新问题以反映相同!
【解决方案2】:

你可以使用:

SELECT *
FROM   table_name
WHERE  CASE WHEN col1 IS NULL THEN 1 ELSE 0 END
       + CASE WHEN col2 IS NULL THEN 1 ELSE 0 END
       + CASE WHEN col3 IS NULL THEN 1 ELSE 0 END
       + CASE WHEN col4 IS NULL THEN 1 ELSE 0 END
       > 0;

或者,只是:

SELECT *
FROM   table_name
WHERE  ( col1 IS NULL OR col2 IS NULL OR col3 IS NULL OR col4 IS NULL );

或者,如果您想排除完全是 NULLs 的行,那么:

SELECT *
FROM   table_name
WHERE  CASE WHEN col1 IS NULL THEN 1 ELSE 0 END
       + CASE WHEN col2 IS NULL THEN 1 ELSE 0 END
       + CASE WHEN col3 IS NULL THEN 1 ELSE 0 END
       + CASE WHEN col4 IS NULL THEN 1 ELSE 0 END
       BETWEEN 1 AND 3;

SELECT *
FROM   table_name
WHERE  ( col1 IS NULL OR col2 IS NULL OR col3 IS NULL OR col4 IS NULL )
AND    NOT ( col1 IS NULL AND col2 IS NULL AND col3 IS NULL AND col4 IS NULL );

如果在四列上创建索引:

CREATE INDEX table_name__idx ON table_name ( col1, col2, col3, col4 );

那么底部查询可以执行为INDEX FULL SCAN,如解释计划所示:

|计划表输出 | | :------------------------------------------------ ---------------------------------------------------- | |计划哈希值:1211442363 | | | | -------------------------------------------------- ---------------------------------- | | |身份证 |操作 |姓名 |行 |字节 |成本 (%CPU)|时间 | | | -------------------------------------------------- ---------------------------------- | | | 0 |选择声明 | | 6 | 60 | 1 (0)| 00:00:01 | | | |* 1 |索引全扫描 | TABLE_NAME__IDX | 6 | 60 | 1 (0)| 00:00:01 | | | -------------------------------------------------- ---------------------------------- |

db小提琴here

使用函数(例如CASEGREATEST)会阻止Oracle 使用索引。

【讨论】:

    【解决方案3】:

    我想你想要:

    select t.*
    from t
    where col1 is null or col2 is null or col3 is null or col4 is null;
    

    请注意,= null&lt;&gt; null 在 SQL 中没有意义。几乎所有与null 的比较都会返回null——在where 子句和case 表达式中被视为“假”。这就是 SQL 提供特殊运算符 is nullis not null 的原因。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-14
      • 2012-05-25
      • 1970-01-01
      • 2012-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多