andriod sqlite BigDecimal:从双精度或文本转换而不会损失精度

时间:2017-10-05 19:09:51

标签: android sqlite android-database

创建表格Foo(productName文本,价格数字)

如何在Android中将价格转换为BigDecimal?

new BigDecimal(cursor.getString(1))

or 

new BigDecimal(cursor.getDouble(1))

它不应该失去精确度。

1 个答案:

答案 0 :(得分:0)

简而言之,不失精度的唯一方法是在保存NUMERIC列的数据时欺骗SQlite。

假设值 1234567890.1234567890 SQLite将根据数字亲和关系将其存储为字符串或双精度: -

  

具有NUMERIC亲和力的列可能包含使用全部五个值的值   存储类。当文本数据插入NUMERIC列时,   文本的存储类转换为INTEGER或REAL(按顺序)   (如果这种转换是无损且可逆的)。对于   SQLite认为,TEXT和REAL存储类之间的转换   如果前15个转换为无损且可逆转   保留该数字的有效十进制数字。如果   无法将TEXT无损转换为INTEGER或REAL   使用TEXT存储类存储该值。没有尝试   转换NULL或BLOB值。

Datatypes In SQLite Version 3 - 3. Type Affinity

通过 getDouble 检索值会导致精度损失,从而导致大十进制值传递 1234567890.1234567165374755859375 (请参阅下面的输出)。

通过 getString 检索值会导致精度下降,从而导致大十进制值传递 1.23457e + 09 (请参阅下面的输出)。

如何欺骗SQLite

解决这个问题的方法是 傻瓜 SQLITE,例如保存 MYNUMB = 1234567890.1234567890 ,将保存为TEXT,然后可以检索为原始字符串,剥离MYNUMB =并用于设置BIG DECIMAL 1234567890.1234567890

以下代码可能会引起关注或使用,并用于确定上述代码: -

MainActivity

public class MainActivity extends AppCompatActivity {

    DBHelper mydbhlpr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Get DBHelper
        mydbhlpr = new DBHelper(this);
        // Empty table
        mydbhlpr.getWritableDatabase().delete(DBHelper.TBNAME,null,null);

        // Insert value as a string
        ContentValues cv = new ContentValues();
        cv.put(DBHelper.PRODUCTNAME_COL,"myproduct");
        cv.put(DBHelper.PRICE_COL,"1234567890.1234567890");
        cv.put(DBHelper.COMMENTS_COL,"DATA INPUT AS STRING");
        mydbhlpr.insertRow(cv);
        cv.clear();

        // insert value as a double
        cv.put(DBHelper.PRODUCTNAME_COL,"myproduct");
        cv.put(DBHelper.PRICE_COL,1234567890.1234567890D);
        cv.put(DBHelper.COMMENTS_COL,"DATA INPUT AS DOUBLE");
        mydbhlpr.insertRow(cv);

        // alternative insert method with value as a string
        mydbhlpr.getWritableDatabase().execSQL(
                "INSERT INTO " + DBHelper.TBNAME + "(" +
                        DBHelper.PRODUCTNAME_COL + "," +
                        DBHelper.PRICE_COL + "," +
                        DBHelper.COMMENTS_COL +
                        ")" +
                        " VALUES('myproduct','1234567890.1234567890','ALTERNATE INPUT STR')"
        );

        // alternative insert method with value as numeric (i.e. not in quotes)
        mydbhlpr.getWritableDatabase().execSQL(
                "INSERT INTO " + DBHelper.TBNAME + "(" +
                        DBHelper.PRODUCTNAME_COL + "," +
                        DBHelper.PRICE_COL + "," +
                        DBHelper.COMMENTS_COL +
                        ")" +
                        " VALUES('myproduct',1234567890.1234567890,'ALTERNATE INPUT NUM')"
        );

        // method to force store numeric data (would need to strip MYNUM= before convert)
        mydbhlpr.getWritableDatabase().execSQL(
                "INSERT INTO " + DBHelper.TBNAME + "(" +
                        DBHelper.PRODUCTNAME_COL + "," +
                        DBHelper.PRICE_COL + "," +
                        DBHelper.COMMENTS_COL +
                        ")" +
                        " VALUES('myproduct','MYNUM=1234567890.1234567890','FOOLIT INPUT NUM')"
        );

        mydbhlpr.retrieveData();
    }
}

这基本上用5行填充表(参见DBHelper),然后调用retrieveData方法将转换结果输出到表中每行的Log。

DBHelper

public class DBHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "bigdecimal";
    public static final String TBNAME = "bd";
    public static final String PRODUCTNAME_COL = "productName";
    public static final String PRICE_COL = "price";
    public static final String COMMENTS_COL = "comments";


    public static final int DBVERSION = 1;
    SQLiteDatabase mDB;

    DBHelper(Context context) {
        super(context,DBNAME,null,DBVERSION);
        mDB = this.getWritableDatabase();
    }
    @Override
    public void onCreate(SQLiteDatabase db) {

        String tblcrtsql = "CREATE TABLE IF NOT EXISTS " + TBNAME + "(" +
                PRODUCTNAME_COL + " TEXT, " +
                PRICE_COL + " NUMERIC, " +
                COMMENTS_COL + " TEXT" +
                ")";
        db.execSQL(tblcrtsql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }

    public void insertRow(ContentValues cv) {
        mDB.insert(TBNAME,null,cv);
    }

    public void retrieveData() {
        String priceasstr;
        Double priceasdbl;
        BigDecimal bdstrprice, bddblprice;
        DecimalFormat df = new DecimalFormat("#.000000000000");

        Cursor csr = mDB.query(TBNAME,null,null,null,null,null,null);
        while (csr.moveToNext()) {
            priceasstr = csr.getString(csr.getColumnIndex(PRICE_COL));
            priceasdbl = csr.getDouble(csr.getColumnIndex(PRICE_COL));
            try {
                bdstrprice = new BigDecimal(priceasstr);
            } catch (Exception e) {
                Log.d("OOOPS","extracted data not a valid number");
                String extracted = priceasstr.substring(6);
                bdstrprice = new BigDecimal(extracted);
            }

            bddblprice = new BigDecimal(priceasdbl);
            Log.d("ROWINFO",
                    "Row = " + Integer.toString(csr.getPosition()) +
                            ". Commentary: " + csr.getString(csr.getColumnIndex(COMMENTS_COL)) +
                            "\n\tValue extracted as String = " + priceasstr +
                            "\n\tValue extracted as Double = " + Double.toString(priceasdbl) +
                            "\n\t  formatted  from Double  = " + df.format(priceasdbl) +
                            "\n\tBD via getString          = " + bdstrprice.toString() +
                            "\n\tBD via getDouble          = " + bddblprice.toString() +
                            "\n\tBDF via getString         = " + df.format(bdstrprice) +
                            "\n\tBDF via getDouble         = " + df.format(bddblprice)
            );
        }
        csr.close();
    }
}

输出

10-05 18:41:18.392 4535-4535/mjt.so46593121 D/ROWINFO: Row = 0. Commentary: DATA INPUT AS STRING
                                                        Value extracted as String = 1.23457e+09
                                                        Value extracted as Double = 1.2345678901234567E9
                                                          formatted  from Double  = 1234567890.123456700000
                                                        BD via getString          = 1.23457E+9
                                                        BD via getDouble          = 1234567890.1234567165374755859375
                                                        BDF via getString         = 1234570000.000000000000
                                                        BDF via getDouble         = 1234567890.123456716537
10-05 18:41:18.392 4535-4535/mjt.so46593121 D/ROWINFO: Row = 1. Commentary: DATA INPUT AS DOUBLE
                                                        Value extracted as String = 1.23457e+09
                                                        Value extracted as Double = 1.2345678901234567E9
                                                          formatted  from Double  = 1234567890.123456700000
                                                        BD via getString          = 1.23457E+9
                                                        BD via getDouble          = 1234567890.1234567165374755859375
                                                        BDF via getString         = 1234570000.000000000000
                                                        BDF via getDouble         = 1234567890.123456716537
10-05 18:41:18.392 4535-4535/mjt.so46593121 D/ROWINFO: Row = 2. Commentary: ALTERNATE INPUT STR
                                                        Value extracted as String = 1.23457e+09
                                                        Value extracted as Double = 1.2345678901234567E9
                                                          formatted  from Double  = 1234567890.123456700000
                                                        BD via getString          = 1.23457E+9
                                                        BD via getDouble          = 1234567890.1234567165374755859375
                                                        BDF via getString         = 1234570000.000000000000
                                                        BDF via getDouble         = 1234567890.123456716537
10-05 18:41:18.392 4535-4535/mjt.so46593121 D/ROWINFO: Row = 3. Commentary: ALTERNATE INPUT NUM
                                                        Value extracted as String = 1.23457e+09
                                                        Value extracted as Double = 1.2345678901234567E9
                                                          formatted  from Double  = 1234567890.123456700000
                                                        BD via getString          = 1.23457E+9
                                                        BD via getDouble          = 1234567890.1234567165374755859375
                                                        BDF via getString         = 1234570000.000000000000
                                                        BDF via getDouble         = 1234567890.123456716537
10-05 18:41:18.392 4535-4535/mjt.so46593121 D/OOOPS: extracted data not a valid number
10-05 18:41:18.392 4535-4535/mjt.so46593121 D/ROWINFO: Row = 4. Commentary: FOOLIT INPUT NUM
                                                        Value extracted as String = MYNUM=1234567890.1234567890
                                                        Value extracted as Double = 0.0
                                                          formatted  from Double  = .000000000000
                                                        BD via getString          = 1234567890.1234567890
                                                        BD via getDouble          = 0
                                                        BDF via getString         = 1234567890.123456789000
                                                        BDF via getDouble         = .000000000000