How to format a Float number in SQLite? - sqlite

In SQLite I need to format a number to display it with the thousand separator and decimal separator. Example: The number 123456789 should be displayed as 1,234,567.89
What I did partially works because it does not display the thousand separator as I expected:
select *, printf ("U$%.2f", CAST(unit_val AS FLOAT) / 100) AS u_val FROM items;
u_val shows: U$1234567.89 but I need U$1,234,567.89

The following is one way that you could accomplish the result:-
select *, printf ("U$%.2f", CAST(unit_val AS FLOAT) / 100) AS u_val FROM items;
Could become :-
SELECT
*,
CASE
WHEN len < 9 THEN myfloat
WHEN len> 8 AND len < 12 THEN substr(myfloat,1,len - 6)||','||substr(myfloat,len - 5)
WHEN len > 11 AND len < 15 THEN substr(myfloat,1,len -9)||','||substr(myfloat,len-8,3)||','||substr(myfloat,len-5)
WHEN len > 14 AND len < 18 THEN substr(myfloat,1,len - 12)||','||substr(myfloat,len -11,3)||','||substr(myfloat,len-8,3)||','||substr(myfloat,len-5)
END AS u_val
FROM
(
SELECT *, length(myfloat) AS len
FROM
(
SELECT *,printf("U$%.2f",CAST(unit_val AS FLOAT) / 100)) AS myfloat
FROM Items
)
)
The innermost SELECT extracts the original data plus a new column as per your orginal SELECT.
The intermediate SELECT adds another column for the length of the new column as derived from unit_val via the printf (this could have been done in the first/innermost SELECT, getting this value simplifies (in my opinion) the outermost SELECT, or you could use multiple length(myfloats) in the outermost SELECT).
RESULT - Example
The following is the result from a testing (source column is myfloat) :-
The highlighted columns being the original columns.
The circled data being the result.
The other 2 columns are intermediate columns.
Edit
As you've clarified that the input is an integer, then :-
SELECT *,'U$'||printf('%,d',(unit_val/100))||'.'||CAST((unit_val % 100) AS INTEGER) AS u_val FROM Items
would work assuming that you are using at least version 3.18 of SQLite.
Correction
Using the SQL immediately above if the value of the last part (the cents) is less than 10 then the leading 0 is dropped. So the correct SQL is. Note for simplicity the CAST has also been dropped and rather than concatening the . it has been added to the printf formatter string so :-
SELECT
'U$' ||
printf('%,d', (unit_val / 100)) ||
printf('.%02d',unit_val % 100)
AS u_val
FROM Items
Or as a single line
SELECT 'U$' || printf('%,d', (unit_val / 100)) || printf('.%02d',unit_val % 100) AS u_val FROM Items

Here is a suggestion:
WITH cte AS (SELECT 123456789 AS unit_val)
SELECT printf('%,d.%02d', unit_val/100, unit_val%100) FROM cte;
The Common Table Expression is just there to supply a dummy value, in the absence of variables.
The %,d format adds thousands separators, but, as many have pointed out, only for integers. Because of that, you will need to use the unit_val twice, once for the integer part, and again to calculate the decimal part.
SQLite truncates integer division, so unit_val/100 gives you your dollar part. The % operator is a remainder operator (not strictly the same as “mod”), so unit_val%100 gives the cents part, as another integer. The %02d format ensures that this is always 2 digits, padding with zeroes if necessary.

Related

Teradata : using case statement in Where clause

My question is about using case statement in where clause to check for date and assign values to columns. My sample code include.
select * from table
where
column 1 > 10 and
case when column 2 = 1
then
column 3<= 10 and column 4 between (1st day of prev month) and (prev month end) or column 5 = '8888-01-01'
else
column 4 between (1st day of this month) and (yesterday)
end ;
when I am running this code. I am getting 3706 syntax error:expected something in between field and '='.
How to fix this ?
A CASE statement will always return a value or NULL (if none of the conditions matches), so you can use it in your WHERE clause. There are a couple ways to format your CASE statement:
Format 1
CASE
WHEN <condition> THEN <some_expression>
WHEN <another_condition> THEN <another_expression>
ELSE <final_expression>
END
-- Example
CASE
WHEN col1 = 10 THEN 'Y'
WHEN col1 = 20 THEN 'N'
ELSE 'N/A'
END
Format 2
CASE <expression>
WHEN <value> THEN <expression>
WHEN <another_value> THEN <another_expression>
ELSE <final_expression>
END
-- Example
CASE col1
WHEN 10 THEN 'Y'
WHEN 20 THEN 'N'
ELSE 'NA'
END
I'm not sure what you're trying to do with your sample code, but it looks more like pseudo-code and will not work as-is. Your CASE statement is not formatted properly and your column references like column 1 will not work that way. If your column is actually named column 1, then you need to put double-quotes around it:
select * from table where "column 1" > 10
Can you please describe a little more clearly what exactly you are trying to do?
A CASE expression can't be used to create some kind of dynamic conditions. Write it as a bunch of AND/OR conditons:
select * from table
where
column 1 > 10 and
(
( column 2 = 1 and
(column 3<= 10 and column 4 between (1st day of prev month) and (prev month end) or column 5 = '8888-01-01')
)
or
column 4 between (1st day of this month) and (yesterday)
);
Double check the logic, the precedence of logical operators is
parenthesis
NOT
AND
OR

Oracle PL SQL - Sort column value beginning with '_" then followed by alphabets

Using Oracle SQL, I want to sort the below data with values beginning with "_" followed by alphabet (without using COLLATE)
AE
BASMI1_02
CBPBC_01
_TYPERR
AE1_01
AE1_03
AEPS
AEYN
ASAS1TABLE
ASAS1_01
CBPBC_01B
CM
as
_TYPERR
AE
AE1_01
AE1_03
AEPS
AEYN
ASAS1_01
ASAS1TABLE
BASMI1_02
CBPBC_01
CBPBC_01B
CM
Try this:
select *
from table
order by case
when col like '\_%' escape '\'
then 0
else 1
end,
col;
It defines a custom sort order using case Statement
If you want the underscore values to be sorted as well then do a union separating the two, simply put:
SELECT * FROM table
WHERE col LIKE '\_%'
ORDER BY col
UNION
SELECT * FROM table
WHERE col NOT LIKE '\_%'
ORDER BY col;

Cognos Substr with varying lengths

I have an ID field that is just numbers but the ID's vary in length. If the number is 16 characters long then I need to display 'x' + last 4 of the ID, if not then just display the last 10 of the ID.
If your ID field is already a string:
CASE character_length([ID])
WHEN 16 THEN 'x' || substring([ID],character_length([ID]) - 3)
ELSE substring([ID],character_length([ID]) - 9)
END
If your ID is stored as an integer, I'd recommend creating a new data item that casts it as a varchar (say named 'ID String'):
CAST([ID],VARCHAR(16))
Then substitute the new value in the first expression:
CASE character_length([ID String])
WHEN 16 THEN 'x' || substring([ID String],character_length([ID String]) - 3)
ELSE substring([ID String],character_length([ID String]) - 9)
END

How to convert the Long value to String using sql

I am doing a long to string conversion using java in following way.
Long longValue = 367L;
String str = Long.toString(longValue, 36).toUpperCase();
this is returning me as value A7. how can achieve this in doing oracle sql.
UPDATED:
Hi, I have analyzed how java code is working then wanted to implement the same thing in procedure.
First point is Input vaues. LONG and Radix. in my case Radix is 36. so i will have values from 1..9A...Z0 It picks up the values from this set only.
Second point Long value as input. we have to divide this value with radix. if the quotient is more than 36 again we need to divide.
For eaxmple 367 then my converted value is 10(quotient) 7(remainder) that is A7.
3672 converted value is 102 0 i need to do again for 102 that is 2 -6 so my final value will be 2-6 0 that is 2U0(- means reverse the order).
UPDATE 2:
Using oracle built in functions we can do this. this was solved by my friend and gave me a function.I want to thank my friend. this will give me an out put as follows.
367 then my converted value is 10(quotient) 7(remainder) that is *A*7.(I modified this to my requirement).
FUNCTION ENCODE_STRING(BASE_STRING IN VARCHAR2,
FROM_BASE IN NUMBER,
TO_BASE IN NUMBER)
RETURN VARCHAR2
IS
V_ENCODED_STRING VARCHAR(100);
BEGIN
WITH N1 AS (
SELECT SUM((CASE
WHEN C BETWEEN '0' AND '9'
THEN TO_NUMBER(C)
ELSE
ASCII(C) - ASCII('A') + 10
END) * POWER(FROM_BASE, LEN - RN)
) AS THE_NUM
FROM (SELECT SUBSTR(BASE_STRING, ROWNUM, 1) C, LENGTH(BASE_STRING) LEN, ROWNUM RN
FROM DUAL
CONNECT BY ROWNUM <= LENGTH(BASE_STRING))
),
N2 AS (
SELECT (CASE
WHEN N < 10
THEN TO_CHAR(N)
ELSE CHR(ASCII('A') + N - 10)
END) AS DIGI, RN
FROM (SELECT MOD(TRUNC(THE_NUM/POWER(TO_BASE, ROWNUM - 1)), TO_BASE) N, ROWNUM RN
FROM N1
CONNECT BY ROWNUM <= TRUNC(LOG(TO_BASE, THE_NUM)) + 1)
)
SELECT SYS_CONNECT_BY_PATH(DIGI, '*') INTO V_ENCODED_STRING
FROM N2
WHERE RN = 1
START WITH RN = (SELECT MAX(RN) FROM N2)
CONNECT BY RN = PRIOR RN - 1;
RETURN V_ENCODED_STRING;
IN PL/SQL (or Oracle SQL) you have the a function called TO_CHAR.
http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions181.htm
It is not possible to do it in the pure SQL. You have to use PL/SQL.
Simple example how to do it PL/SQL:
CREATE TABLE long_tbl
(
long_col LONG
);
INSERT INTO long_tbl VALUES('How to convert the Long value to String using sql');
DECLARE
l_varchar VARCHAR2(32767);
BEGIN
SELECT long_col
INTO l_varchar
FROM long_tbl;
DBMS_OUTPUT.PUT_LINE(l_varchar);
END;
-- How to convert the Long value to String using sql
There is TO_LOB function but it can only by used when you insert data into table.
http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions185.htm
You can apply this function only to a LONG or LONG RAW column, and
only in the select list of a subquery in an INSERT statement.
There is also other, more proper way to do it by using "dbms_sql.column_value_long" but this gets complicated (fetching of the LONG column and appending to the CLOB type.)
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_sql.htm#i1025399
(Oracle Database PL/SQL Packages and Types Reference)

How can I calculate the median of values in SQLite?

I'd like to calculate the median value in a numeric row. How can I do that in SQLite 4?
Let's say that the median is the element in the middle of an ordered list.
SQLite (4 or 3) does not have any built-in function for that, but it's possible to do this by hand:
SELECT x
FROM MyTable
ORDER BY x
LIMIT 1
OFFSET (SELECT COUNT(*)
FROM MyTable) / 2
When there is an even number of records, it is common to define the median as the average of the two middle records.
In this case, the average can be computed like this:
SELECT AVG(x)
FROM (SELECT x
FROM MyTable
ORDER BY x
LIMIT 2
OFFSET (SELECT (COUNT(*) - 1) / 2
FROM MyTable))
Combining the odd and even cases then results in this:
SELECT AVG(x)
FROM (SELECT x
FROM MyTable
ORDER BY x
LIMIT 2 - (SELECT COUNT(*) FROM MyTable) % 2 -- odd 1, even 2
OFFSET (SELECT (COUNT(*) - 1) / 2
FROM MyTable))
There is an extension pack of various math functions for sqlite3. It includes group functions like median.
It will be more work getting this going than CL's answer, but might be worthwhile if you think you will need any of the other functions.
http://www.sqlite.org/contrib/download/extension-functions.c?get=25
(Here is the guide for how to compile and load SQLite extensions.)
From description:
Provide mathematical and string extension functions for SQL queries using the loadable extensions mechanism. Math: acos, asin, atan, atn2, atan2, acosh, asinh, atanh, difference, degrees, radians, cos, sin, tan, cot, cosh, sinh, tanh, coth, exp, log, log10, power, sign, sqrt, square, ceil, floor, pi. String: replicate, charindex, leftstr, rightstr, ltrim, rtrim, trim, replace, reverse, proper, padl, padr, padc, strfilter. Aggregate: stdev, variance, mode, median, lower_quartile, upper_quartile.
UPDATE 2015-04-12: Fixing "undefined symbol: sinh"
As has been mentioned in comments, this extension may not work properly despite a successful compile.
For example, compiling may work and on Linux you might copy the resulting .so file to /usr/local/lib. But .load /usr/local/lib/libsqlitefunctions from the sqlite3 shell may then generate this error:
Error: /usr/local/lib/libsqlitefunctions.so: undefined symbol: sinh
Compiling it this way seems to work:
gcc -fPIC -shared extension-functions.c -o libsqlitefunctions.so -lm
And copying the .so file to /usr/local/lib shows no similar error:
sqlite> .load /usr/local/lib/libsqlitefunctions
sqlite> select cos(pi()/4.0);
---> 0.707106781186548
I'm not sure why the order of options to gcc matters in this particular case, but apparently it does.
Credit for noticing this goes to Ludvick Lidicky's comment on this blog post
There is a log table with timestamp, label, and latency. We want to see the latency median value of each label, grouped by timestamp. Format all latency value to 15 char length with leading zeroes, concatenate it, and cut half positioned value(s).. there is the median.
select L, --V,
case when C % 2 = 0 then
( substr( V, ( C - 1 ) * 15 + 1, 15) * 1 + substr( V, C * 15 + 1, 15) * 1 ) / 2
else
substr( V, C * 15 + 1, 15) * 1
end as MEDST
from (
select L, group_concat(ST, "") as V, count(ST) / 2 as C
from (
select label as L,
substr( timeStamp, 1, 8) * 1 as T,
printf( '%015d',latency) as ST
from log
where label not like '%-%' and responseMessage = 'OK'
order by L, T, ST ) as XX
group by L
) as YY
Dixtroy provided the best solution via group_concat().
Here is a full sample for this:
DROP TABLE [t];
CREATE TABLE [t] (name, value INT);
INSERT INTO t VALUES ('A', 2);
INSERT INTO t VALUES ('A', 3);
INSERT INTO t VALUES ('B', 4);
INSERT INTO t VALUES ('B', 5);
INSERT INTO t VALUES ('B', 6);
INSERT INTO t VALUES ('C', 7);
results into this table:
name|value
A|2
A|3
B|4
B|5
B|6
C|7
now we use the (slightly modified) query from Dextroy:
SELECT name, --string_list, count, middle,
CASE WHEN count%2=0 THEN
0.5 * substr(string_list, middle-10, 10) + 0.5 * substr(string_list, middle, 10)
ELSE
1.0 * substr(string_list, middle, 10)
END AS median
FROM (
SELECT name,
group_concat(value_string,"") AS string_list,
count() AS count,
1 + 10*(count()/2) AS middle
FROM (
SELECT name,
printf( '%010d',value) AS value_string
FROM [t]
ORDER BY name,value_string
)
GROUP BY name
);
...and get this result:
name|median
A|2.5
B|5.0
C|7.0
If you are using PDO then ::loadExtension() used in Paul's answer might not be available to you.
Assuming you are using PHP, an alternative is to create an aggregate function.
$pdo_handle->sqliteCreateAggregate(
'median', // the name of the function to declare
function($context, $row_number, $value){ // a method called for each row
$context[] = $value; // store the values
return $context;
},
function($context, $row_count){ // a method called once all row have been iterated over
// sort the values
sort($context, SORT_NUMERIC);
// cound the number of values
$count = count($context);
// get the mid point of array (lowest one)
$middle = floor($count/2);
// if there is an even amount of values
if (($count % 2) == 0) {
// average the two middle values to find the median
return ($context[$middle--] + $context[$middle])/2;
} else {
// odd amount of elements, so the median value is simply the one in the middle
return $context[$middle];
}
},
1
);
You are then free to do a
SELECT median("column_name") FROM "table_name";
Similar "create function" might be available in other languages.
The SELECT AVG(x) returns just the year of date values formatted as YYYY-MM-DD, so I tweaked CL's solution just slightly to accommodate dates:
SELECT DATE(JULIANDAY(MIN(MyDate)) + (JULIANDAY(MAX(MyDate)) - JULIANDAY(MIN(MyDate)))/2) as Median_Date
FROM (
SELECT MyDate
FROM MyTable
ORDER BY MyDate
LIMIT 2 - ((SELECT COUNT(*) FROM MyTable) % 2) -- odd 1, even 2
OFFSET (SELECT (COUNT(*) - 1) / 2 FROM MyTable)
);

Resources