PAYATHON 2026

如何在 Oracle 中用 MEDIAN 填充 NULL 并创建新表?

数据小陈

使用 NVL 和 MEDIAN 分析函数即可

在一条 CREATE TABLE ... AS SELECT 语句中即可完成替换,无须分别查询 NULL 和非 NULL 数据,也不需要使用 UNION:

CREATE TABLE NEW_TABLE AS
SELECT
    PK_ID,
    NVL(COLUMN_NAME, MEDIAN(COLUMN_NAME) OVER ()) AS COLUMN_NAME
FROM TABLE_ORIGIN;

这条语句会创建新表,保留原表的每一行和已有的非 NULL 值,并将 COLUMN_NAME 中的 NULL 替换为整列的中位数。原表 TABLE_ORIGIN 不会被修改。

为什么这样写有效?

MEDIAN(COLUMN_NAME) OVER () 是分析函数写法。空的 OVER () 以整个查询结果为计算范围,让每一行都能取得相同的中位数,同时保留各行的 PK_ID。

MEDIAN 计算时会忽略 NULL,外层的 NVL 负责选择最终值:

  • COLUMN_NAME 非 NULL 时,保留原值。
  • COLUMN_NAME 为 NULL 时,使用计算出的中位数。

例如,原列包含 10、20、100、NULL,非 NULL 值的中位数为 20,新表中的对应数据就是 10、20、100、20。

也可以使用 COALESCE 实现相同的逻辑:

CREATE TABLE NEW_TABLE AS
SELECT
    PK_ID,
    COALESCE(COLUMN_NAME, MEDIAN(COLUMN_NAME) OVER ()) AS COLUMN_NAME
FROM TABLE_ORIGIN;

两种写法任选一种执行即可。Oracle SQL Developer 是执行 SQL 的客户端,计算由 Oracle Database 完成。

原 SQL 有哪些问题?

原代码先通过 TEMP_MEDIAN 计算中位数,再拆分 NULL 和非 NULL 行。其中,WITH 定义的是命名查询结果,并不会创建多张临时表。

代码中还有两个直接影响结果的问题:

  1. TEMP NULL AS (...) 中的名称包含未加引号的空格,语法不正确。如果保留这个查询结构,应使用类似 TEMP_NULL 的合法名称。
  2. UNION 的第二部分仍然读取 TEMP_NOT_NULL T0,因此会再次选择非 NULL 行,并将这些行的值替换为中位数。真正需要填充的 NULL 行没有进入最终结果。

修正这些问题后,也可以直接用分析函数保留所有行,再由 NVL 完成替换,无须拆分后重新合并。

使用时需要注意什么?

如果整列都是 NULL,MEDIAN(COLUMN_NAME) OVER () 的结果也是 NULL,新表中的这些值仍然是 NULL。此时无法从原数据中得到有效的中位数,需要另行确定默认值。

如果非 NULL 值的数量为偶数,中位数取排序后中间两个值的平均值,结果可能包含小数。后续如果要写入精度受限的数值列,需要考虑小数位和舍入规则。

CREATE TABLE ... AS SELECT 不会自动复制原表的主键约束。如果 NEW_TABLE.PK_ID 也需要作为主键,可以在建表后执行:

ALTER TABLE NEW_TABLE
ADD CONSTRAINT NEW_TABLE_PK PRIMARY KEY (PK_ID);

备注:内容仅供参考。