concat two int values in postgresql - postgresql

I have 7 integer values (with 3,1,3,4,4,5,4 digits respectively) and I have to concatenate them to a single integer (i.e a 24 digit no.) . I tried to do it like this
create or replace function gen_id(int,int,int,int,int,int,int) returns bigint as $$
declare
id bigint;
begin
id = $1 * 1000000000000000000000 + $2 * 100000000000000000000 + $3 * 100000000000000000 + $4 * 10000000000000 + $5 * 1000000000 + $6 * 10000 + $7;
return id;
end;
$$ language plpgsql;
select * from gen_id(100,1,101,1000,1001,10001,1000);
But when I execute it I get error: bigint out of range . Is there any other better way to do it ?
thanks

What about:
SELECT CAST(CAST(num1 AS text)||CAST(num2 AS text)||... AS numeric(24,0))
If you happen to have your IDs in some table, then you can do:
SELECT CAST(string_agg(CAST(num AS text), '') AS numeric(24,0)) FROM srctab;

As I can concatenate a string to integer
SELECT REPLACE(STR(ISNULL(MAX(usuarioid) + 1, 1), 6), ' ', '0') FROM usuarios
usuarioid is string + 1

Related

plpgsql $[position] is relative?

create or replace function exc_using(int, text) returns int as
$$
declare i int;
begin
for i in execute 'select * from generate_series(1,$1) ' using $1+1 loop
raise notice '% ', i;
raise notice 'i + i *3: % ', i + i * 3;
end loop;
execute 'select $2 + $2 * 3 + length($1) '
into i using $2, $1;
return i;
end
$$
language plpgsql;
seems A
execute 'select $2 + $2 * 3 + length($1) '
into i using $2, $1;
return i;
is the same as:
B
execute 'select $1 + $1 * 3 + length($2) '
into i using $1, $2;
return i;
My preception is that $2 Absolutely refer to function second argument that data type is text. but seems plpgsql $[position] is relative. But I cannot get manual reference for this edge case.
Of course they are relative. What else would they be? But what are they relative to?
Inside the EXECUTE string, the $1 and $2 are relative to the USING. Outside, they are relative to the function parameters.

get rank of players' height in plpgsql

We are going to have the rank of height, but I got 0 for all players
I convert the feet and inches into cm first, and use the sample code teacher gave us.
Here is my code:
CREATE OR REPLACE FUNCTION player_height_rank (firstname VARCHAR, lastname VARCHAR) RETURNS int AS $$
DECLARE
rank INTEGER:= 0;
offset INTEGER:= 0;
tempValue FLOAT:= NULL;
r record;
BEGIN
FOR r IN SELECT ((p.h_feet * 30.48) + (p.h_inches * 2.54)) AS height, p.firstname, p.lastname
FROM players p
ORDER BY ((p.h_feet * 30.48) + (p.h_inches * 2.54)) DESC, p.firstname, p.lastname
LOOP
IF r.height = tempValue then
offset := offset + 1;
ELSE
rank := rank + offset + 1;
offset := 0;
tempValue := r.height;
END IF;
IF r.firstname = $1 AND r.lastname = $2 THEN
RETURN rank;
END IF;
END LOOP;
-- not in DB
RETURN 0;
END;
$$ LANGUAGE plpgsql;
--select * from player_height_rank('Ming', 'Yao');
Your function works fine for me if I correct two bugs:
One of your commas is not really a comma, but a “fullwidth comma”, UNICODE code point FF0C, which causes a syntax error.
You have a variable name offset, which causes SQL syntax errors because it is a reserved key word in SQL. If you really need to use that name, you have to enclose it in double quotes (") throughout, but it is better to choose a different name.
The reason this causes a problem is that an assignment like offset := offset + 1; in PL/pgSQL is translated into an SQL statement like SELECT offset + 1 INTO offset;.
You can do the whole thing in a single SQL query, which is more efficient:
SELECT rank
FROM (SELECT firstname,
lastname,
rank() OVER (ORDER BY h_feet + 12 * h_inches)
FROM players
) dummy
WHERE firstname = 'Ming'
AND lastname = 'Yao';

Invalid length parameter passed to the SUBSTRING function

I have written the query and it is working:
declare #word as nvarchar (20)
set #word = 'victOR aALEXander'
select upper(left(#word, 1)) + lower(SUBSTRING(#word,2,charindex(' ', #word)-2)) + ' ' +
upper(left(substring(#word,charindex(' ', #word)+1,len(#word)-1),1))
+ lower(SUBSTRING(#word,charindex(' ', #word)+2, len(#word)))
I have created the function:
alter function letters ( #word as nvarchar(20))
returns varchar(20) as begin
return upper(left(#word, 1)) + lower(SUBSTRING(#word,2,charindex(' ', #word)-2)) + ' ' +
upper(left(substring(#word,charindex(' ', #word)+1,len(#word)-1),1))
+ lower(SUBSTRING(#word,charindex(' ', #word)+2, len(#word))) end
Finally i have done:
select dbo.letters(users)
from dbo.tempdb
I have got:
Invalid length parameter passed to the SUBSTRING function
Why?
Try this function:
Create Function dbo.Proper(#Data VarChar(8000))
Returns VarChar(8000)
As
Begin
Declare #Position Int
Select #Data = Stuff(Lower(#Data), 1, 1, Upper(Left(#Data, 1))),
#Position = PatIndex('%[^a-zA-Z][a-z]%', #Data COLLATE Latin1_General_Bin)
While #Position > 0
Select #Data = Stuff(#Data, #Position, 2, Upper(SubString(#Data, #Position, 2))),
#Position = PatIndex('%[^a-zA-Z][a-z]%', #Data COLLATE Latin1_General_Bin)
Return #Data
End
This function works properly whether there are spaces, apostrophes, or anything else in your data. Unfortunately it won't convert macdonald to MacDonald or o'brien to O'Brien. However, it will work for any word(s) that only have 1 capital letter in it.
also try trimming in case you have spaces at the beginning and end:
alter function letters ( #word as nvarchar(20))
returns varchar(20) as
begin
set #word = ltrim(rtrim(#word))
return upper(left(#word, 1)) + lower(SUBSTRING(#word,2,charindex(' ', #word)-2)) + ' ' +
upper(left(substring(#word,charindex(' ', #word)+1,len(#word)-1),1))
+ lower(SUBSTRING(#word,charindex(' ', #word)+2, len(#word)))
end
Character count of #word parameter is less than substring count. Also, parameter could be null.
try if this query works. However if you have more than single ' ' then this query will fail.
declare #word as nvarchar (20)
set #word = 'alex' -- 'victOR aALEXander'
select
upper(left(#word, 1)) +
CASE WHEN charindex(' ', #word)>0 THEN lower(SUBSTRING(#word,2,charindex(' ', #word)-2)) + ' '
+ upper(left(substring(#word,charindex(' ', #word)+1,len(#word)-1),1))
+ lower(SUBSTRING(#word,charindex(' ', #word)+2, len(#word)))
ELSE lower(SUBSTRING(#word,2,len(#word)-1)) END

NULLIF check for empty string returns empty string with a column name, but NULL with the column value

I have a database column set to char(255) (yes, CHAR. Don't ask me why that's how the database was set up) that at present has an empty string with two spaces (i.e. " "). Using NULLIF(LTRIM(RTRIM(column_name)), '') does NOT work (the output is [two empty spaces]). However, using NULLIF(' ', '') works correctly and the output is NULL. In other words, the actual column value works correctly, while passing the name of the column returns an incorrect value.
Any ideas on this?
I believe the column must have more than just spaces. For example:
CREATE TABLE #x(id INT, y CHAR(255));
INSERT #X SELECT 1, ' '
UNION ALL SELECT 2, ' '
UNION ALL SELECT 3, ' ' + CHAR(9);
SELECT id, NULLIF(LTRIM(RTRIM(y)),'') FROM #x;
Results:
1 NULL
2 NULL
3
For a row where this fails, try this:
DECLARE #s CHAR(255);
SELECT #s = y FROM #x WHERE id = 3;
DECLARE #i INT;
SET #i = 1;
WHILE #i <= DATALENGTH(#s)
BEGIN
IF ASCII(SUBSTRING(#s, #i, 1)) <> 32
BEGIN
PRINT 'Position ' + RTRIM(#i) + ' = CHAR('
+ RTRIM(ASCII(SUBSTRING(#s, #i, 1))) + ')';
END
SET #i = #i + 1;
END
It should tell you what other characters are in there, and where.

Convert IP address in PostgreSQL to integer?

Is there a query that would be able to accomplish this?
For example given an entry '216.55.82.34' ..I would want to split the string by the '.'s, and apply the equation:
IP Number = 16777216*w + 65536*x + 256*y + z
where IP Address = w.x.y.z
Would this be possible from just a Query?
You can simply convert inet data-type to bigint: (inet_column - '0.0.0.0'::inet)
For example:
SELECT ('127.0.0.1'::inet - '0.0.0.0'::inet) as ip_integer
will output 2130706433, which is the integer representation of IP address 127.0.0.1
You can use split_part(). For example:
CREATE FUNCTION ip2int(text) RETURNS bigint AS $$
SELECT split_part($1,'.',1)::bigint*16777216 + split_part($1,'.',2)::bigint*65536 +
split_part($1,'.',3)::bigint*256 + split_part($1,'.',4)::bigint;
$$ LANGUAGE SQL IMMUTABLE RETURNS NULL ON NULL INPUT;
SELECT ip2int('200.233.1.2');
>> 3370713346
Or, if don't want to define a function, simply :
SELECT split_part(ip,'.',1)::bigint*16777216 + split_part(ip,'.',2)::bigint*65536 +
split_part(ip,'.',3)::bigint*256 + split_part(ip,'.',4)::bigint;
The drawback of the later is that, if the value is given by some computation instead of being just a table field, it can be inefficient to compute, or ugly to write.
PG 9.4
create or replace function ip2numeric(ip varchar) returns numeric AS
$$
DECLARE
ip_numeric numeric;
BEGIN
EXECUTE format('SELECT inet %L - %L', ip, '0.0.0.0') into ip_numeric;
return ip_numeric;
END;
$$ LANGUAGE plpgsql;
Usage
select ip2numeric('192.168.1.2');
$ 3232235778
create function dbo.fn_ipv4_to_int( p_ip text)
returns int
as $func$
select cast(case when cast( split_part(p_ip, '.', 1 ) as int ) >= 128
then
(
( 256 - cast(split_part(p_ip, '.', 1 ) as int ))
*
-power ( 2, 24 )
)
+ (cast( split_part(p_ip, '.', 2 ) as int ) * 65536 )
+ (cast( split_part(p_ip, '.', 3 ) as int ) * 256 )
+ (cast( split_part(p_ip, '.', 4 ) as int ) )
else (cast(split_part(p_ip, '.', 1 ) as int) * 16777216)
+ (cast(split_part(p_ip, '.', 2 ) as int) * 65536)
+ (cast(split_part(p_ip, '.', 3 ) as int) * 256)
+ (cast(split_part(p_ip, '.', 4 ) as int))
end as int )
$func$ LANGUAGE SQL IMMUTABLE RETURNS NULL ON NULL INPUT;
in case you need to get a 32 bit int. it'll return negative numbers for ips over 128.0.0.0. I'd use bigint if you can, but i had a case when i had the numbers stored as 32 bit numbers from another database.
Consider changing the column data type to inet, maybe is more efficient.
ALTER TABLE iptable ALTER COLUMN ip_from TYPE inet
USING '0.0.0.0'::inet + ip_from::bigint;
create index on iptable using gist (ip_from inet_ops);
Then to query
SELECT ip_from
FROM iptable
WHERE ip_from = '177.99.194.234'::inet