【问题标题】:About COALESCE in PostgreSQL and handling Null Values关于 PostgreSQL 中的 COALESCE 和处理 Null 值
【发布时间】:2020-07-23 06:24:15
【问题描述】:

我正在使用 PostgreSQL 练习 SQL,但我在使用 COALESCE 时遇到了问题,也许有人可以告诉我哪里出错了。

我有一个包含四列的表格:title、height_cm、length_cm 和 width_cm。我想将最后三个相乘并得到“大小”列。问题是整个数据集有许多 NULL 值和 0,我想跳过并返回三列可能的最大值(即,如果只有高度有值,则返回该值,如果三列有值乘以三)。如果没有列有值,则返回“NO VALUE FOUND”。

我无法管理“跳过” Null 值(我还没有真正从 0 开始,因为我一开始就被困住了)。我以为这样可以解决问题,但它没有用。

 SELECT title, height_cm, length_cm, width_cm, 
        COALESCE(
        height_cm * length_cm * width_cm, 
        length_cm * width_cm, 
        height_cm * length_cm, 
        height_cm * width_cm, 
        height_cm, 
        length_cm, 
        width_cm, 'NO VALUE FOUND') AS size
FROM artworks
ORDER BY size ASC
LIMIT 10

首先,系统不识别“NO VALUE FOUND”(但是当我添加一个0时,它会识别它),其次,当我取出文本时,系统仍然认为NULL值。我能够让它工作添加

WHERE height_cm IS NOT NULL AND length_cm IS NOT NULL AND width_cm IS NOT NULL

但我认为 COALESCE 的主要思想是能够跳过 NULL 值。有什么建议吗?

关于0,如果我添加:

WHERE height_cm != 0 AND length_cm != 0 AND width_cm != 0

我丢失了具有值但也有一个 0 的行。

谢谢!

使用答案中的解决方案进行编辑

最后我使用了 CTE 结合下面帮助过的人的答案,这是最终的查询:

WITH query AS (SELECT title, height_cm, length_cm, width_cm, 
        (CASE WHEN height_cm IS NULL AND length_cm IS NULL AND width_cm IS NULL
        THEN 0
        ELSE (COALESCE(height_cm, 1) * COALESCE(length_cm, 1) * COALESCE(width_cm, 1))
        END) AS size
        FROM artworks)
        
SELECT *
FROM query
WHERE size > 0
ORDER BY size ASC
LIMIT 10

【问题讨论】:

    标签: sql postgresql null coalesce


    【解决方案1】:

    传递给 coalesce 的所有元素的数据类型应该相同,但我会将coalesce 应用于每一列单独,如果是1,则使用默认值1

    coalesce(height_cm, 1) * coalesce(length_cm, 1) * coalesce(width_cm, 1) as size
    

    这在逻辑上与您编码的内容相同。

    如果它们全部 null,您需要进行特殊检查,您也可以(ab)使用coalesce

    case
        when coalesce(height_cm, length_cm, width_cm) is null then null -- or 0
        else coalesce(height_cm, 1) * coalesce(length_cm, 1) * coalesce(width_cm, 1)
    end as size
    

    当它们都是null 时,您必须选择null 或一些特殊值(例如0)。您可以按照自己的意愿将其呈现为“NO VALUE FOUND”给用户。

    【讨论】:

    • 感谢 Bohemian,我能够使用 0 并使用 CTE 使其工作(我编辑我的问题以显示最终查询)。菜鸟问题,我想过滤掉具有 0 的行,并且在我写的 size > 0 子句中的 WHERE 中,为什么在不使用 CTE 的情况下查询不能将别名“大小”识别为列?查询的读取顺序是从下到上吗?
    • 大多数数据库不允许在 where 子句中引用选择表达式别名。尽管不方便并且它不会杀死开发人员来支持它,但这是有道理的,因为 where 子句是结果行上的 filter,它在原始数据 before 被渲染时触发通过用于选定值的表达式。如果它受到支持,则如果使用该表达式,则性能会受到影响,因为该表达式是针对连接结果中的每一行进行评估的,即使不在最终结果行中也是如此。通过强制编码人员重复 where 子句中的表达式,性能下降的可能性就显而易见了。
    【解决方案2】:

    “NO VALUE FOUND”另一方面是字符串类型 0 是数字,这就是为什么当您使用 0 时它不会产生问题,因为在 0 的情况下,该列的所有数据都是数字数据类型,但是当您是尝试使用字符串时,会产生混合两种不同数据类型的问题,这是 sql 引擎不允许的

    【讨论】:

    • 谢谢 Zaynul,有没有办法解决这个问题?
    【解决方案3】:

    我同意 Bohemian 关于使用单一表达式的观点。但是,我认为您想要的最终表达式返回一个字符串:

    (case when height_cm is null and length_cm is null and width_cm is null
          then 'NO VALUE FOUND'
          else (coalesce(height_cm, 1) * coalesce(length_cm, 1) * coalesce(width_cm, 1))::text
     end) as size
    

    或者,只使用 NULL 值,这意味着该值不可用。

    【讨论】:

    • 感谢 Gordon,添加文本效果很好,这正是我想要的。但是,后来我意识到我无法过滤掉底部值,这是我的错误,因为我实际上想从结果中删除那些值为 0 的值,所以“文本”选项对我来说是个坏主意边。无论如何,您的回答有助于了解双冒号“::”来更改数据类型。谢谢!
    【解决方案4】:

    听起来你在这里真正想使用的函数是GREATEST

    SELECT
        title,
        height_cm,
        length_cm,
        width_cm, 
        COALESCE(
            GREATEST(
                height_cm * length_cm * width_cm,
                length_cm * width_cm,
                height_cm * length_cm,
                height_cm * width_cm,
                height_cm,
                length_cm,
                width_cm)::text, 'NO VALUE FOUND') AS size
    FROM artworks
    ORDER BY size
    LIMIT 10;
    

    GREATEST 函数将自动获取最大的 NULL 值。因此,对于高度、长度和宽度恰好同时为 NULL 的情况,您只需要在这里将COALESCE 作为一个包罗万象的情况。

    【讨论】:

    • 嗨蒂姆,谢谢你,有什么办法可以解决“找不到值”,当我说:“数字类型的输入语法无效:"NO VALUE FOUND" LINE 15: width_cm), 'NO VALUE FOUND') AS size,还有一个问题不是GREATEST 歪曲小于 0 的值吗?例如 0.6 * 0.5 是 0.3,但当前查询将返回 0.6。对此有何建议?
    • @JourneyDS 抱歉,您需要将算术表达式转换为文本。 CASE 表达式的所有分支必须具有相同的类型。
    猜你喜欢
    • 2015-02-13
    • 2012-09-30
    • 2021-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-14
    • 1970-01-01
    • 2017-01-23
    相关资源
    最近更新 更多