简体   繁体   中英

Unexpected behaviour for saving the value in decimal column in clickhouse

When save the value (0.0003) in decimal column (Decimal(12,4)) in Clickhouse, the saved value was 0.0002.
Why is it behaved like this?
But when I did insert by SQL directly, I was able to save it without a problem.
Which means, the go program that I wrote is wrong?

■ create table

CREATE TABLE test_ch (
    id Decimal(12,4),
    created_at DateTime
) ENGINE = MergeTree() PARTITION BY toYYYYMMDD(created_at) ORDER BY (created_at);

■ source

import (
    "database/sql"
    "fmt"
    "time"

    "github.com/ClickHouse/clickhouse-go"
    sq "github.com/Masterminds/squirrel"
)

var ConnectCH *sql.DB

func main() {
    SetClickHouse()
    insert()
}

func insert() error {
    return Exec(func(tx *sql.Tx) error {
        prepare, _, _ := sq.Insert("test_ch").
            Columns(
                "id",
                "created_at",
            ).Values().ToSql()
        stmt, _ := tx.Prepare(prepare)

        createdAt := time.Now().Format("2006-01-02 15:04:05")
        if _, err := stmt.Exec(
            0.0003,
            createdAt,
        ); err != nil {
            return err
        }
        return nil
    })
}

func recoverAndRollback(tx *sql.Tx) {
    if r := recover(); r != nil {
        tx.Rollback()
    }
}

func Exec(t func(*sql.Tx) error) error {
    tx, err := ConnectCH.Begin()
    if err != nil {
        tx.Rollback()
        return err
    }
    defer recoverAndRollback(tx)
    if err := t(tx); err != nil {
        tx.Rollback()
        return err
    }
    if err := tx.Commit(); err != nil {
        tx.Rollback()
        return err
    }
    return nil
}

func SetClickHouse() error {
    var err error

    url := fmt.Sprintf("tcp://%s:%s", "clickhouse", "9000")
    ConnectCH, err = sql.Open("clickhouse", url)
    if err != nil {
        return err
    }

    if err := ConnectCH.Ping(); err != nil {
        if exception, ok := err.(*clickhouse.Exception); ok {
            fmt.Printf("[%d] %s \n%s\n", exception.Code, exception.Message, exception.StackTrace)
        } else {
            fmt.Println(err)
        }
        return err
    }

    return nil
}

■ output

when id = 0.0001
SELECT *
FROM test_ch

┌─────id─┬──────────created_at─┐
│ 0.0002 │ 2020-01-09 01:59:33 │
└────────┴─────────────────────┘

is OK

when id = 0.0002
 SELECT * FROM test_ch ┌─────id─┬──────────created_at─┐ │ 0.0002 │ 2020-01-09 01:59:33 │ └────────┴─────────────────────┘

is OK

when id = 0.0003
 SELECT * FROM test_ch ┌─────id─┬──────────created_at─┐ │ 0.0002 │ 2020-01-09 02:00:30 │ └────────┴─────────────────────┘

Why is it 0.0002?

performance

SELECT CAST(toFloat64('0.0003'), 'Decimal(12, 8)')    
┌─CAST(toFloat64('0.0003'), 'Decimal(12, 8)')─┐
│                                  0.00029999 │
└─────────────────────────────────────────────┘


SELECT CAST('0.0003', 'Decimal(12, 8)')
┌─CAST('0.0003', 'Decimal(12, 8)')─┐
│                       0.00030000 │
└──────────────────────────────────┘

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM