【问题标题】:How to insert a decimal number with Diesel's PgNumeric type?如何用 Diesel 的 PgNumeric 类型插入十进制数?
【发布时间】:2016-11-05 15:07:18
【问题描述】:

对于如何将PgNumeric 类型用于十进制数,我感到很困惑。我在tests 中注意到1.0-31.0 使用以下实例插入到表中:

PgNumeric::Positive { weight: 0, scale: 1, digits: vec![1] } 

PgNumeric::Negative  {weight: 0, scale: 1, digits: vec![31] }

我似乎不知道如何将带有小数点右侧数字的值(如5.4321)插入到表格中。

【问题讨论】:

  • 让 Diesel 做任何我想让它做的事情……具有挑战性。您确定需要直接使用对象而不是 "1.0::numeric" 之类的东西吗?

标签: rust rust-diesel


【解决方案1】:

简答:PgNumeric::Positive { weight: 0, scale: 4, digits: [5, 4321] }

更多示例:

// 9.87654321::numeric
PgNumeric::Positive { weight: 0, scale: 8, digits: [9, 8765, 4321] }

// 12345.6789::numeric
PgNumeric::Positive { weight: 1, scale: 4, digits: [1, 2345, 6789] }

// 100000000.000000002::numeric
PgNumeric::Positive { weight: 2, scale: 9, digits: [1, 0, 0, 0, 0, 2000] }

// 0.3::numeric
PgNumeric::Positive { weight: -1, scale: 1, digits: [3000] }

看起来算法是:

  1. 将您的号码分组为从小数点开始并向外扩展的 4 位数字块。这些是数字

  2. 计算表示整数部分所需的数并减一。这是重量

  3. 计算表示小数部分所需的位数。这是规模

测试工具

这是我正在使用的代码,从测试中提取:

extern crate diesel;

use diesel::*;
use diesel::types::*;

use diesel::pg::data_types::PgNumeric;
use diesel::pg::PgConnection;

 type PgBackend = <PgConnection as Connection>::Backend;

fn main() {
    let query = "100000000.000000002::numeric";
    let expected_value = PgNumeric::Negative {
        digits: vec![31],
        weight: 0,
        scale: 1,
    };
    assert_eq!(expected_value, query_single_value::<Numeric, PgNumeric>(query));
}

fn query_single_value<T, U: Queryable<T, PgBackend>>(sql_str: &str) -> U
    where PgBackend: HasSqlType<T>,
{
    use diesel::expression::dsl::sql;
    let connection = connection();
    select(sql::<T>(sql_str)).first(&connection).unwrap()
}

fn connection() -> PgConnection {
    let result = connection_without_transaction();
    result.begin_test_transaction().unwrap();
    result
}

fn connection_without_transaction() -> PgConnection {
    let connection_url = "postgres://localhost/some_db";
    ::diesel::pg::PgConnection::establish(&connection_url).unwrap()
}

可能有用的背景信息

来自Postgres docs

数字的刻度是小数部分中小数位数的计数,位于小数点右侧。数值的precision是整数中有效位数的总和,即小数点两边的位数。所以数字 23.5141 的精度为 6,小数位数为 4。

但是,Postgres code 说:

/*
 * In the NumericShort format, the remaining 14 bits of the header word
 * (n_short.n_header) are allocated as follows: 1 for sign (positive or
 * negative), 6 for dynamic scale, and 7 for weight.  In practice, most
 * commonly-encountered values can be represented this way.
 *
 * In the NumericLong format, the remaining 14 bits of the header word
 * (n_long.n_sign_dscale) represent the display scale; and the weight is
 * stored separately in n_weight.
 */

【讨论】:

  • 只是想补充一点,并提到PgNumeric 并不是真正设计为供用户直接使用的。相反,它是它如何存储在 PG 中的直接表示。这类似于我们的 PgTimestamp 类型,我们的更高级别的 impl 是基于它构建的,但用户应该使用 chrono::NaiveDateTimestd::time::SystemTime 代替。不同之处在于我们没有序列化的更高级别的东西。如果有一个合理的 bigdecimal crate 可以使用,很高兴添加。
猜你喜欢
  • 1970-01-01
  • 2018-03-02
  • 1970-01-01
  • 1970-01-01
  • 2015-05-04
  • 2014-10-17
  • 2016-09-19
  • 1970-01-01
  • 2014-01-04
相关资源
最近更新 更多