How to covert substring to integer? - postgresql

I have varchar data then i want to convert it to integer so i can using the number to order my data this is my varchar
No.SKF.4-04/2021/CBO-ODSP
No.SKF.5-04/2021/CBO-ODSP
No.SKF.6-04/2021/CBO-ODSP
`
i want to take the number so i can select order the data
SELECT varchar from account_information order by CAST(substring(left("NO_SURAT", "length"("NO_SURAT")-17),8)as integer)
but it show some error
SELECT CAST(substring(left("NO_SURAT", "length"("NO_SURAT")-17),8)as integer) from account_information
ERROR: invalid input syntax for type integer: ""
how do i covert substring result to int?

Avoiding an expensive regular expression, you could use:
SELECT CAST(
substr(
'No.SKF.5-04/2021/CBO-ODSP',
8,
position('-' IN 'No.SKF.5-04/2021/CBO-ODSP') - 8
) AS integer
);
substr
════════
5
(1 row)

Related

Convert a bytea into a binary string

I need to decode a base64 string and take a chunk of binary.
Is there a SQL function in Postgres to simply convert a bytea into a binary string representation?
(Like "00010001010101010".)
If your Postgres installation runs with the default setting bytea_output = 'hex', there is a very simple hack:
SELECT right(bytea_col::text, -1)::varbit;
Example:
SELECT right((bytea '\xDEADBEEF')::text, -1)::varbit;
Result:
'11011110101011011011111011101111'
right(text, -1) is just the cheapest way to remove the leading backslash from the text representation.
varbit (standard SQL name bit varying) is for bit strings of arbitrary length. Cast the result to text or varchar if you like.
Related, with explanation:
Convert hex in text representation to decimal number
demo:db<>fiddle
You could put the following code into a function:
WITH byte AS ( -- 1
SELECT E'\\xDEADBEEF'::bytea as value
)
SELECT
string_agg( -- 5
get_byte(value, gs)::bit(8)::text -- 4
, ''
)
FROM
byte,
generate_series( -- 3
0,
length(value) - 1 -- 2
) gs
I demonstrated the development of the query within the fiddle.
The WITH clause encapsulates the bytea value for double usage in further code
length() calculates the binary length of the bytea value
generate_series() creates a list from 0 to length - 1 (0 - 3 in my example)
get_byte() takes the bytea value a second time and gives out the byte at position gs (the previous calculated values 0-3). This gives an integer representation of the the byte. After that the cast to bit(8) type converts the result of this function to its binary representation (1 byte = 8 bit)
string_agg() finally aggregates all for binary strings into one. (taking its text representations instead of bit type, with no delimiters)
A function could look like this:
CREATE OR REPLACE FUNCTION to_bit(value bytea) RETURNS SETOF text AS
$$
BEGIN
RETURN QUERY
SELECT
string_agg(get_byte(value, gs)::bit(8)::text, '')
FROM
generate_series(0, length(value) - 1) gs;
END;
$$ LANGUAGE plpgsql;
After that you could call it:
SELECT to_bit(E'\\xDEADBEEF'::bytea)
You could try it using get_bit() instead of get_byte(). This safes you the ::bit(8) cast but of course you need to multiply the length with factor 8 indeed.
The resulting bit string has another bit order but maybe it fits your use case better:
WITH byte AS (
SELECT E'\\xDEADBEEF'::bytea as value
)
SELECT
string_agg(get_bit(value, gs)::text, '')
FROM
byte,
generate_series(0, length(value) * 8 - 1) gs
demo:db<>fiddle

How to extract timestamp from mongodb objectid in postgres

In MongoDB you can retrieve the date from an ObjectId using the getTimestamp() function. How can I retrieve the date from a MongoDB ObjectId using Postgresql (e.g., in the case where such an ObjectId is stored in a Postgres database)?
Example input:
507c7f79bcf86cd7994f6c0e
Wanted output:
2012-10-15T21:26:17Z
In Mongodb documentation the Objectid is formed with a timestamp as the first 4 bytes, but this is represented in hexidecimal. Assuming that hexidecimal value is stored as a string in PostgreSQL, then the following query will extract just the first 8 characters of that objectid, convert that to an integer (which is seconds from 1970-01-01) then convert that integer to a timestamp. For example:
SELECT TO_TIMESTAMP(int_val) ts_val
FROM (
SELECT ('x' || lpad(left(objectid,8), 8, '0'))::bit(32)::int AS int_val
FROM (
VALUES ('507c7f79bcf86cd7994f6c0e')
) AS t1(objectid)
) AS t2
;
Converting a hexadecimal string to integer is discussed here:
Convert hex in text representation to decimal number
The first answer is quite excellent. This one expands the answer by making a reusable function out of it.
create function extractMongoTimestamp(text) RETURNS TIMESTAMP WITH TIME ZONE
as
'SELECT TO_TIMESTAMP(int_val) ts_val
FROM (
SELECT (''x'' || lpad(left(objectid,8), 8, ''0''))::bit(32)::int AS int_val
FROM (
VALUES ($1)
) AS t1(objectid)
) AS t2'
language sql
immutable
RETURNS null on null input;
Use it in your query:
select extractMongoTimestamp('507c7f79bcf86cd7994f6c0e');

Postgres: ERROR: operator does not exist: character varying = bigint

My query is something like this. I try to get a status for a list of ids.
select order_number, order_status_name
from data.order_fact s
join data.order_status_dim l
on s.order_status_key = l.order_status_key
where
order_number in (1512011196169,1512011760019,1512011898493,1512011972111)
I get an error though that says:
ERROR: operator does not exist: character varying = bigint
LINE 6: order_number in (1512011196169,1512011760019,1512011898493,1...
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Do you have any clue on how I should reform the ids to get it work?
Thanks a lot!
Your order_number is a varchar, you can't compare that to a number (123 is a number in SQL, '123' is a string constant)
You need to use string literals:
order_number in ('1512011196169','1512011760019','1512011898493','1512011972111')
More details in the manual:
http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS
If you can't change the type of numbers within in, you could use cast:
select * from numbers_as_string
where cast(my_numbers_as_string as int) in (1,2,3)
This happen too when you are using native query in sprinboot and you are passing a parameter as string but that field is a (integer or long) in your model/entity, also when you are comparing a string with a integer due that param is used like string without casting.
so you should cast it as integer in the native query like this
x\:\:integer
for example:
#Query(value="
......
.....
inner join tablex t on t.x\\:\\:integer = pv.id \n"+
....
....
")
List<Object> getMyQuery(#Param("x") String x)

Postgres convert from bytea which contains float (IEEE 754) to real (float4)

The following SQL SELECT query returns an integer:
SELECT (((get_byte(dalsk.data, 0)::bit(8)) ||
(get_byte(dalsk.data, 1)::bit(8)) ||
(get_byte(dalsk.data, 2)::bit(8)) ||
get_byte(dalsk.data, 3)::bit(8)) :: bit(32)) :: integer --AS rezult_float
FROM (SELECT substring(data from 2 for 5) AS data FROM raw_data WHERE
raw_data_id = 33)
AS dalsk;
Whenever I try to cast the result from integer to real, I get the following error:
Cannot cast type bit to real.
Is there a way to convert the value to float?
The IEEE754 doesn't cover endianess so that's not enough info to convert the binary to float. If you want to convert it you will have to create a function or a cast operator.

Problem converting nvarchar to decimal t-sql

I'm trying to convert nvarchar to decimal (18,2) and I'm receiving the following message:
Msg 8115, Level 16, State 6, Line 2
Arithmetic overflow error converting nvarchar to data type numeric.
The CAST is: CAST(bm_onnet AS decimal(18,2)) as bm_onnet_corr,
it works only if the value has only maximum 3 decimals, doesn't work for value below:
21.8333333333333333333333333333333333333
How should I modify my SELECT?
Use the round function
example
declare #v nvarchar(100) = '21.8333333333333333333333333333333333333'
select convert(decimal(18,2),round(#v,2))
a select would look like this
SELECT CAST(round(bm_onnet,2) AS decimal(18,2)) as bm_onnet_corr
select
case when charindex('.',bm_onnet)) > = 2 then
convert(decimal(18,2),substring(bm_onnet,0,charindex('.',bm_onnet)+3))
else
convert(decimal(18,2),bm_onnet)
end
too early in the morning use this instead.