【问题标题】:Store int, float and boolean in same database column将 int、float 和 boolean 存储在同一数据库列中
【发布时间】:2022-10-04 20:49:04
【问题描述】:

在 Postgres 的同一列中存储 int、float 和 boolean 值是否有合理的方法?
如果有类似的东西:

rid time value
2d9c5bdc-dfc5-4ce5-888f-59d06b5065d0 2021-01-01 00:00:10.000000 +00:00 true
039264ad-af42-43a0-806b-294c878827fe 2020-01-03 10:00:00.000000 +00:00 2
b3b1f808-d3c3-4b6a-8fe6-c9f5af61d517 2021-01-01 00:00:10.000000 +00:00 43.2

目前我正在使用 jsonb 来存储它,但是现在的问题是,我无法使用更大的运算符在表中进行过滤。

查询

SELECT * 
FROM points 
WHERE value > 0;

返回错误:

ERROR: operator does not exist: jsonb > integer: No operator matches the given name and argument types. You might need to add explicit type casts.

对我来说,在 truefalse 的情况下将布尔值处理为 1 或 0 是可以的。是否有可能使用 jsonb 实现这一目标,或者是否有另一种超级类型可以让我使用能够使用所有三种类型的列?

性能在这里不是那么重要,因为我在该表中将有很少的记录,我猜最多 5k。

【问题讨论】:

  • 如果你想使用>,那应该如何使用true?这真的是一个领域还是两个领域,甚至三个领域?
  • 如果没有看到value 的示例,就没有太多可以做的答案。也没有解释为什么要在列中混合类型?对我来说,这是糟糕设计的标志。

标签: sql json postgresql jsonb


【解决方案1】:

如果您只是存储整数和浮点数,通常您会使用 floatnumeric 列。

但是有那个讨厌的true

你可以转换 JSON ......

select *
from test
where value::float > 1;

...但是有那个讨厌的true

您必须将布尔值转换为数字才能使其工作。

select *
from test
where
  (case when value = 'true' then 1.0 when value = 'false' then 0.0 else value::float end) >= 1;

或者忽略它。

必须绕过类型系统表明value 实际上是将两个甚至三个不同的字段塞进一个。考虑将它们分成多列。

【讨论】:

    【解决方案2】:

    您应该跳过value 不是number 的行并将值转换为numeric,例如:

    with points(id, value) as (
    values
        (1, 'true'::jsonb),
        (2, '2'),
        (3, '43.2')
    )
    
    select *
    from points
    where jsonb_typeof(value) = 'number'
    and value::text::numeric > 0;
    
     id | value
    ----+-------
      2 | 2
      3 | 43.2
    (2 rows)
    

    【讨论】:

      【解决方案3】:

      我实际上发现,无论 jsonb 字段值如何,您都可以将其与 postgres 中的其他 jsonb 进行比较。这意味着,例如,我可以执行以下操作:

      SELECT *
      FROM points
      WHERE val > '5'
      

      这正确地只给了我第三行。它只是忽略了bool 值。要过滤某个布尔值,我可以使用以下查询来实现:

      SELECT *
      FROM points
      WHERE val = 'true'
      

      这对我来说已经足够好了。我什至可以在 json 列中保存时间戳并使用这种方法进行比较。
      在您的所有 cmets 似乎是使该列成为数字之后解决问题的另一种方法。这也可以,但需要更多的客户端转换,因为我必须有第二个类型列,记住实际类型是什么。应该在客户端使用此类型将值转换回其 og 值。对于整数来说它是微不足道的,对于像@schwern 建议的布尔值,可以使用10,对于日期,可以使用unix 时间戳表示。

      当我现在想要搜索某个值时,type 也必须包含在 where 子句中。

      【讨论】:

        猜你喜欢
        • 2018-06-29
        • 2016-08-11
        • 2018-12-31
        • 2022-12-17
        • 1970-01-01
        • 2014-12-17
        • 1970-01-01
        • 1970-01-01
        • 2015-01-06
        相关资源
        最近更新 更多