Oracle - 用另一列中的值填充列中的空值

Posted

技术标签:

【中文标题】Oracle - 用另一列中的值填充列中的空值【英文标题】:Oracle - Fill null values in a column with values from another column 【发布时间】:2020-01-13 09:05:41 【问题描述】:

我使用的是 Oracle 11.1.1.9.0,我的目标是用每个产品(即产品列中的 A、B 和 C)在“原材料”列中的第一个 NOT NULL 值填充 Null 值。此请求的末尾说明了示例表和预期结果。

以下代码集均无效:

代码 1:

IFNULL(Raw Materials,
       First_value(Raw Materials) OVER (PARTITION BY Product))

代码 2:

IFNULL(Raw Materials, 
        First_value(Raw Materials) OVER (PARTITION BY Product 
                       RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW))

代码 3:

COALESCE(lag(Raw Materials ignore null) OVER (partition by Product), 
         Raw Materials)

代码 4:

IFNULL(Raw Materials, EVALUATE('LAG(%1, 1) OVER (PARTITION BY %2)' AS varchar2(20), Raw Materials, Product))

注意:IFNULL 函数在环境中确实有效。使用 IFNULL(Raw Materials, '1') 对其进行了测试,结果是 Raw Materials 列中的所有空值都变为 1。

谢谢。

+---------+----------+ +---------+----------+ |产品 |材料 | |产品 |材料 | +---------+----------+ +---------+----------+ |一个 | | |一个 |苹果 | |一个 | | |一个 |苹果 | |一个 | | |一个 |苹果 | |一个 | | |一个 |苹果 | |一个 |苹果 | |一个 |苹果 | |乙| | |乙|橙色 | |乙| | |乙|橙色 | |乙| | => |乙|橙色 | |乙| | |乙|橙色 | |乙|橙色 | |乙|橙色 | | C | | | C |香蕉 | | C | | | C |香蕉 | | C | | | C |香蕉 | | C | | | C |香蕉 | | C |香蕉 | | C |香蕉 | +---------+----------+ +---------+----------+ 左边是示例表数据。正确的是预期的结果。

以下链接“Oracle 代码环境”显示了Oracle 逻辑SQL 函数的代码环境和示例。 Oracle code environment

Oracle 逻辑 SQL 手册:https://docs.oracle.com/middleware/11119/biee/BIEUG/appsql.htm#CHDDCFJI

【问题讨论】:

Oracle 没有IFNULL 函数。如果您在前两个选项中将IFNULL 换成COALESCE,那么您的代码就会起作用。 您认为哪一行“第一”?我在你的表情中看不到ORDER BY。每个产品可以有不同的材料吗?如果是这样,请在您的请求中添加这样的示例。 @MT0 感谢您与我们联系。我正在使用他们的逻辑 SQL 在 OBIEE 下工作,IFNULL 是提供的功能之一。 @ThorstenKettner 感谢您与我们联系。在这种情况下,我只查看每个产品的一个组件。 【参考方案1】:

对于您的数据集,您可以简单地做一个窗口MAX()MIN()

NVL(Raw_Materials, MAX(Raw_Materials) OVER(PARTITION BY Product))

如果您有一个可用于对行进行排序的列(我假设为id),您可以将LAG()IGNORE NULLS 子句一起使用:

NVL(Raw_Materials, LAG(Raw_Materials IGNORE NULLS) OVER(PARTITION BY Product ORDER BY id))

【讨论】:

感谢您与 GMB 联系。我在 OBIEE 环境中尝试了 2 个建议的代码,但没有成功。我用类似的设置测试了 NVL() 函数,它也遇到了错误。我推测 Oracle 中的逻辑 SQL 不理解 NVL()。我也尝试了以下代码,它也导致了错误。关于错误可能在哪里的想法? IFNULL(原材料,评估('LAG(%1, 1) over (PARTITION BY %2)' AS varchar2(20),原材料,项目编号))【参考方案2】:

虽然您说您正在寻找一些“第一”价值,但您的样本数据表明您只是希望所有相同的产品都具有相同的材料:

update mytable m1 set material = 
(
  select min(material)
  from mytable m2
  where m2.product = m1.product
);

如果您只想选择此数据。然后你可以使用这个:

select product, min(material) over (partition by product)
from mytable;

根据文档 (https://docs.oracle.com/cd/E28280_01/bi.1111/e10540/sqlref.htm#BIEMG678),似乎 OBIEE 对分析窗口函数 (e.g. MIN() OVER()) 使用了特殊语法:

select
  product,
  evaluate('min(%1) over (partition by %2)', material, product)
from mytable;

您必须通过相应地查看EVALUATE_SUPPORT_LEVEL 来启用此功能。

(我希望我做对了。否则请阅读有关此的文档并自己尝试一些类似的东西。)

【讨论】:

再次感谢托尔斯滕。在 Oracle OBIEE 中,当我将 MIN () 或 MAX() 放在 Raw Materials 周围时,会导致错误。会不会是因为 MIN() 或 MAX() 在 Oracle OBIEE 环境下不处理字符串? 问题似乎是解析函数MIN OVER。我添加了一个查询,它可能是 OBIEE 中的解决方案。 感谢您对 EVALUATE_SUPPORT_LEVEL 文档的快速迭代和参考。由于错误代码提示 EVALUATE_... 不受支持,我将不得不联系我的系统管理员寻求他的帮助,以启用 EVALUATE_SUPPORT_LEVEL 支持并测试您建议的解决方案。同时,您是如何生成您的建议链接的,在该链接中打开时直接显示页面上的相关内容?而不是在页面顶部打开。 docs.oracle.com/cd/E28280_01/bi.1111/e10540/sqlref.htm#BIEMG678谢谢 那是一个锚点(网址中的#)。在某个站点上时,您有时可以单击指向该站点某个位置的链接。这是 URL 的一部分。在这个例子中,我点击了这样一个链接或被谷歌引导到那里(我不记得了),所以#BIEMG678 成为了 url 的一部分。【参考方案3】:

你可以试试下面的查询,我们使用的是初值分析函数 nullif,COALESCE 等在行级别而不是列级别工作。

with temp as (select 'A' product,NULL raw_material from dual union all
select 'A',NULL from dual union all
select 'A',NULL from dual union all
select 'A',NULL from dual union all
select 'A','APPLE' from dual union all
select 'B',NULL from dual union all
select 'B',NULL from dual union all
select 'B',NULL from dual union all
select 'B',NULL from dual union all
select 'B','ORANGE' from dual union all
select 'C',NULL from dual union all
select 'C',NULL from dual union all
select 'C',NULL from dual union all
select 'C',NULL from dual union all
select 'C',NULL from dual union all
select 'C','Banana' from dual)
select   a.*,FIRST_VALUE(raw_material IGNORE NULLS) 
     OVER (partition by product ORDER BY product) first_product from temp a;

【讨论】:

感谢您与 Bhanu Yadav 联系。示例图表是我案例的简化版本,其中包含数十种产品,并且它们会定期更改。因此,手动编码每个项目代码可能不适用于我的情况。但是,我非常感谢您建议的代码,这可能是未来案例的解决方案! 嗨@JonathanChan,我仅将硬编码值用于工作代码,并且用作临时表。主要代码在 with 子句下方,其中我使用 first_value 和 partition by 子句以及 order by 来区分值。在 select a.*,FIRST_VALUE(raw_material IGNORE NULLS) OVER (partition by product ORDER BY product) first_product from temp a; 感谢您的澄清。虽然 OBIEE 计算度量无法运行此代码,但它绝对适用于标准 SQL 环境。【参考方案4】:

Oracle 没有IFNULL 函数。如果您在前两个代码 sn-ps 中的任何一个中将 IFNULL 换成 COALESCE,您的代码就会起作用:

SELECT t.*,
       COALESCE(
         raw_material,
         FIRST_VALUE(raw_material)
           IGNORE NULLS
           OVER ( PARTITION BY product )
       ) AS updated_raw_material
FROM   test_data t;

输出:

产品 | RAW_MATERIAL | UPDATED_RAW_MATERIAL :-------- | :----------- | :-------------------- 一个 | |苹果 一个 | |苹果 一个 | |苹果 一个 |苹果 |苹果 乙| |橙子 乙| |橙子 乙| |橙子 乙| |橙子 乙|橙色 |橙子 C | |香蕉 C | |香蕉 C | |香蕉 C | |香蕉 C | |香蕉 C |香蕉 |香蕉

db小提琴here

【讨论】:

再次感谢 MT0 建议的代码导致错误。想知道 Oracle 中的逻辑 SQL 不理解代码的哪一部分。我尝试使用以下代码坚持使用 Oracle 的逻辑 SQL,它也导致了错误。你知道错误可能在哪里吗? IFNULL (Raw Materials, EVALUATE ('LAG(%1, 1) over (PARTITION BY %2)' AS varchar2(20), Raw Materials, Item Number))

以上是关于Oracle - 用另一列中的值填充列中的空值的主要内容,如果未能解决你的问题,请参考以下文章

pandas 怎么处理表格中的空值

仅计算两个不同列中的空值并显示在一个选择语句中

第一列中的空值是不是会阻止在 Pentaho Spoon 中导入 Excel 文件?

用另一列中的值替换缺失值

Python,如何使用字典填充数据框中的空值

Apache Spark:如何使用 Java 在 dataFrame 中的空值列中插入数据