How to parse accounting number format in SQLite field? - sqlite

I am a somewhat newbie to SQLite (and KMyMoney). KMyMoney (an open source personal finance manager) allows one-click exporting data into an SQLite database.
On browsing the SQLite database output, the dollar amount data is stored in a table called kmmSplits as several text fields in a strange format based on “value” and “valueFormatted” (see screen shot below). The “value” field is apparently written as a division equation (in a text format) which apparently yields the “valueFormatted” field (again in text format). The “valueFormatted is the correct number amount but the problem is that parenthesis are used to indicate a negative number instead of a simple minus in front of the value. This is apparently an accounting number format, but I don’t know how to parse this into a float value for running calculated SQL queries, etc. The positive values (without parenthesis) are no problem to convert to FLOATS.
I’ve tried using the CAST to FLOAT function but this does not do the division math, nor does it convert parenthesis into negative values (see screen shot).
The basic question is: how to parse a text value containing parenthesis in the “valueFormatted field (accounting money format) into a common number format OR, alternatively, how to convert a division equation in the “value” field to an actual calculation.

Use a CASE expression to check if valueFormatted is a numeric value inside parentheses and if it is multiply -1 with the substring starting from the 2nd char (the closing parenthesis will be discarded by SQLite during this implicit type casting):
SELECT *,
CASE
WHEN valueFormatted LIKE '(%)' THEN (-1) * SUBSTR(valueFormatted, 2)
ELSE valueFormatted
END AS value
FROM kmmSQLite;
Or, replace '(' with ''-'' and add 0 to covert the result to a number:
SELECT *,
REPLACE(valueFormatted, '(', '-') + 0 AS value
FROM kmmSQLite;

Related

SQLite How to handle Negative numbers with Negative Sign at the end

We've never experienced this before. We are importing Tab Delimited TXT files that include numeric columns. Negative numbers have the indicator behind the number and not in front (e.g. 550.00- rather than -550.00).
We are using SQLite Expert Professional. When reviewing the import results in the table, any number with the negative sign in the back was converted to the negative sign in the front but everyone of these cells are highlighted in blue (we are not sure why SQLite Expert is doing this but assume it has meaning). In addition, when querying and summing they are being ignored causing the resulting value to be higher than expected.
The field types are FLOAT and DECIMAL
We have googled and cannot find any results about negative sign location.
Appreciate any assistance on how to handle this.
An UPDATE query could alter the values by subtracting the incorrect value from 0 after replacing the negative sign with nothing.
The UPDATE could be based upon :-
UPDATE vneg SET iv = (0 - replace(iv,'-','')) WHERE instr(iv,'-') > 1;
e.g. :-
DROP TABLE IF EXISTS vneg;
CREATE TABLE IF NOT EXISTS vneg (iv);
INSERT INTO vneg VALUES ('100.35'),('133.44-'),('25.453-');
SELECT * FROM vneg; -- First Result (before)
UPDATE vneg SET iv = (0 - replace(iv,'-','')) WHERE instr(iv,'-') > 1;
SELECT * FROM vneg; -- Second result (after)
Before the update :-
After the Update :-
And then using SELECT sum(iv) AS summed FROM vneg; results in :-
-58.543

How to limit numeric column type to certain symbols before and after decimal separator in sqlite?

I want to limit numeric column type to 10 symbols before decimal separator and 4 symbols after decimal separator. I executed the following command:
ALTER TABLE scustdisc ADD COLUMN spec_price numeric(10,4)
The command executed without errors but when I try to insert value in spec_price 10.123456 I am able to do it. It should give error and the value not to be inserted. Am I wrong in my alter command?
SQLite has a dynamic type system and the column types have a limited impact, but can be virtually any name. They are resolved to one of TEXT, NUMERIC, INTEGER, REAL or BLOB.
numeric(0,0) - numeric(99999999,99999999) and more resolve to NUMERIC.
As such 10,4 4,10 etc means nothing and makes no difference to SQLite.
With one exception bar constraints a column may hold any type of value. The column type only comes into play in determining the way the data is stored.
A must read is Datatypes In SQLite Version 3
You may also find How flexible/restricive are SQLite column types?
You may be able to resolve this by using a CHECK constraint CREATE TABLE or by using a TRIGGER or multiple TRIGGERs.
You could format the number(s) appropriately when they are displayed.
You could utilise the round(x,y) function Core Functions

sqlite3 cast REAL as NUMERIC(x,y)

I have a table with a numeric(6,4) column (x.xxxx)
In the select statement, I have to do math on this column which results in the value being typed as a REAL. I need to display the results using numeric(6,4) though and can't seem to see how to do this.
I tried "cast(column as numeric(6,4))" which works in other databases, but the displayed value is still REAL format with more than 4 digits to the right of the decimal. I need to get it back to the "x.xxxx" format from REAL.

Why some decimal places truncated when insert 1234567890.12345678 into Decimal(18, 8) column in SQLite?

Below is my table create in SQLite database,
CREATE TABLE MyData(
Code VARCHAR(20),
Amount DECIMAL(18, 8)
);
then I insert 2 rows into the table.
INSERT INTO MyData
VALUES('A', 1.12345678);
INSERT INTO MyData
VALUES('B', 1234567890.12345678);
After that, execute a SELECT statement,
SELECT * FROM MyData;
SQLite returns the following result:
A|1.12345678
B|1234567890.12346
The DECIMAL(18, 8) suppose means precision=18 and scale=8, why some decimal places are truncated?
The details of how sqlite stores its data is described here. When you specify the DECIMAL column type, the storage for the column has NUMERIC affinity.
Section 2.0 has the following description about type affinity:
A column with NUMERIC affinity may contain values using all five
storage classes. When text data is inserted into a NUMERIC column, the
storage class of the text is converted to INTEGER or REAL (in order of
preference) if such conversion is lossless and reversible. For
conversions between TEXT and REAL storage classes, SQLite considers
the conversion to be lossless and reversible if the first 15
significant decimal digits of the number are preserved. If the
lossless conversion of TEXT to INTEGER or REAL is not possible then
the value is stored using the TEXT storage class. No attempt is made
to convert NULL or BLOB values.
This indicates that sqlite will attempt conversions between types, and if the first 15 digits of the number can be converted and reversed, the numbers are deemed to be equal. This effectively puts a limit on the available precision with which a number can be stored to 15 significant digits.
The wikipedia article on double precision floating point numbers has additional information which is useful when dealing with floating point numbers.

SQLite: Numeric values in CSV treated as text?

I just imported a huge text file into a table, using the .import command. Everything is OK, except for the fact that it seems to treat clearly numeric values as text. For instance, conditions such as WHERE field > 4 are always met. I did not specify datatypes when I created the table, but this doesn't seem to matter when small tables are created.
Any advice would be welcome. Thanks!
Edit/conclusion: It turns out some of the values in my CSV file were blanks. I ended up solving this by being a bit less lazy and declaring the datatypes explicitly.
The way SQLite handles types is described on this page: http://www.sqlite.org/datatype3.html
In particular:
Under circumstances described below,
the database engine may convert values
between numeric storage classes
(INTEGER and REAL) and TEXT during
query execution.
Section 3.4 (Comparison Example) should give you concrete examples, which are likely to explain the problem you have. This is probably this example:
-- Because column "a" has text affinity, numeric values on the
-- right-hand side of the comparisons are converted to text before
-- the comparison occurs.
SELECT a < 40, a < 60, a < 600 FROM t1;
0|1|1
To avoid the affinity to be guessed, you can use CAST explicitly (see section 3.2 too):
SQLite may attempt to convert values
between the storage classes INTEGER,
REAL, and/or TEXT before performing a
comparison. Whether or not any
conversions are attempted before the
comparison takes place depends on the
affinity of the operands. Operand
affinity is determined by the
following rules:
An expression that is a simple reference to a column value has the
same affinity as the column. Note that
if X and Y.Z are column names, then +X
and +Y.Z are considered expressions
for the purpose of determining
affinity.
An expression of the form "CAST(expr AS type)" has an affinity
that is the same as a column with a
declared type of "type".
Otherwise, an expression has NONE affinity.
Here is another example:
CREATE TABLE test (value TEXT);
INSERT INTO test VALUES(2);
INSERT INTO test VALUES(123);
INSERT INTO test VALUES(500);
SELECT value, value < 4 FROM test;
2|1
123|1
500|0
It's likely that the CSV import create columns of affinity TEXT.

Resources