I need to join the max(id) with is a bigint (and a primary key) from one table to another table. So, if the max id is 1234567890, then I would want the results to be:
name, max_id
'foo', 1234567890
'bar', 1234567890
'noo', 1234567890
'boo', 1234567890
'zoo', 1234567890
My first thought was just to write a function and market it as STABLE
CREATE OR REPLACE FUNCTION get_max_id() RETURNS bigint AS
$$
DECLARE
result bigint;
BEGIN
RAISE NOTICE 'entering get_max_id';
SELECT INTO result max(id) FROM mytable;
RETURN result;
END;
$$
LANGUAGE plpgsql STABLE;
Then I called it via a SQL statement like:
SELECT name, get_max_id() FROM a_really_big_table;
But, from my raise notice, it seems like this is getting called for each each record in a_really_big_table.
What is the best way to write this so that I can keep the PostgreSQL from doing a lookup on mytable for each row in a_really_big_table?
I'm using PostgreSQL 9.4.1
Could it be a solution?
=# SELECT name AS name,
(SELECT MAX(id) FROM your_table) AS max_id
FROM really_big_table;
name │ max_id
──────────────────┼─────────
44e5f8fc1f75fad2 │ 5307021
97fc0aa3a5e3da98 │ 5307021
ccb83afb938ad758 │ 5307021
523bf25914e5c9c0 │ 5307021
d2362badeb2eb7ea │ 5307021
b6e0b87df6d41523 │ 5307021
da754db1fa226453 │ 5307021
865d0e177cb0a3e8 │ 5307021
5904a07a273d8cba │ 5307021
952c75ef37d47dab │ 5307021
(10 rows)
Related
I have the following hexadecimal data that I want to convert using the postgres functions, the data they receive is the following:
#AVLData_TimeStamp #AVLData_GPSElement_Altitude
00000174C0FA7EA0 0140
And I want to convert them to the following data
#MOPO_FECHAHORA #MOPO_ALTITUD
2020-09-24 09:37:56.000 320
I have tried to do it using this function but have not succeeded
SELECT to_timestamp(#AVLData_TimeStamp)
I have two functions in SQLserver that do this but in postgres I don't know how to do it
First Function:
CREATE FUNCTION FUN_Unix_To_Date(
#FechaUnix CHAR(38)
)
RETURNS DATETIME
AS
BEGIN
DECLARE
#LocalTime BIGINT
,#Adjusted BIGINT
,#seconds BIGINT = #FechaUnix
SET #LocalTime = DATEDIFF(MS,GETDATE(),GETUTCDATE())
SET #Adjusted = #seconds - #LocalTime
RETURN (DATEADD(SECOND,CONVERT(BIGINT, LEFT(CAST(#Adjusted AS VARCHAR(100)),13))/1000, CAST('1970-01-01 00:00:00' AS DATETIME)))
END
Two Function:
CREATE FUNCTION HexadecimalToDec_v2(
#hexval CHAR(38)
)
RETURNS NUMERIC(38)
AS
BEGIN
DECLARE #i INT
,#digits INT
,#result NUMERIC
,#current_digit CHAR(1)
,#current_digit_dec NUMERIC
SET #digits = LEN(#hexval)
SET #i = 0
SET #result =0
WHILE #i <= #digits
BEGIN
SET #current_digit = SUBSTRING(#hexval, #i, 1)
IF #current_digit = 'A' OR
#current_digit = 'B' OR
#current_digit = 'C' OR
#current_digit = 'D' OR
#current_digit = 'E' OR
#current_digit = 'F'
SET #current_digit_dec = ASCII(#current_digit) - ASCII('A') + 10
ELSE
SET #current_digit_dec = CONVERT(INT,#current_digit)
SET #result = (#result * 16) + #current_digit_dec
SET #i = #i + 1
END
RETURN(#result)
END
and finally the function is used like this
#MOPO_FECHAHORA = (dbo.Unix_To_Date(dbo.FUN_HexadecimalToDec_v2(#AVLData_TimeStamp)))
And this is the result
#MOPO_FECHAHORA
2020-09-24 09:37:56.000
Thank you very much for your help.
Use the function from this answer to convert hexadecimal to decimal (you might want to use bigint rather than integer):
CREATE OR REPLACE FUNCTION hex_to_int(hexval text) RETURNS bigint
LANGUAGE plpgsql IMMUTABLE STRICT AS
$$DECLARE
result bigint;
BEGIN
EXECUTE 'SELECT x' || quote_literal(hexval) || '::bigint'
INTO result;
RETURN result;
END;$$;
The timestamp can then be converted with
to_timestamp(hex_to_int('00000174C0FA7EA0') / 1000.0)
Just to clarify the source of issue.
The problem is that the your value(s) is the "local" epoch but to_timestamp() function returns timestamp with timezone value. Lets try some example:
with t(x) as (values('2020-09-24 09:37:56'))
select
x::timestamp as srcts,
x::timestamptz as srctstz,
to_timestamp(extract(epoch from x::timestamp)) as cnvts,
to_timestamp(extract(epoch from x::timestamptz)) as cnvtstz
from t;
┌─[ RECORD 1 ]─────────────────────┐
│ srcts │ 2020-09-24 09:37:56 │
│ srctstz │ 2020-09-24 09:37:56+03 │
│ cnvts │ 2020-09-24 12:37:56+03 │ <- Here is the issue in our case
│ cnvtstz │ 2020-09-24 09:37:56+03 │
└─────────┴────────────────────────┘
As you can see the data source type is critical. That's why you got the increased (actually converted from UTC to the local time zone) value in the first try using #LaurenzAlbe answer.
To fix this issue you need to perform some "reverse" calculations:
with t(x) as (values('2020-09-24 09:37:56'))
select
x::timestamp as srcts,
x::timestamptz as srctstz,
to_timestamp(extract(epoch from x::timestamp)) as cnvts,
(to_timestamp(extract(epoch from x::timestamp)))::timestamptz at time zone 'utc' as cnvtsrecalc,
to_timestamp(extract(epoch from x::timestamptz)) as cnvtstz
from t;
┌─[ RECORD 1 ]┬────────────────────────┐
│ srcts │ 2020-09-24 09:37:56 │
│ srctstz │ 2020-09-24 09:37:56+03 │
│ cnvts │ 2020-09-24 12:37:56+03 │ <- Here is the issue in our case
│ cnvtsrecalc │ 2020-09-24 09:37:56 │ <- Issue fixed
│ cnvtstz │ 2020-09-24 09:37:56+03 │
└─────────────┴────────────────────────┘
The following function wraps all this logic including the conversion of the hex value to bigint:
create or replace function hex2ts(text)
returns timestamp
language sql
immutable
strict
as $$
select
(to_timestamp(('x' || lpad($1, 16, '0'))::bit(64)::bigint / 1000.0))::timestamptz at time zone 'utc'
$$;
What is the data type of column_name in information_schema.columns?
i tried this but didnt get
code:
CREATE OR REPLACE FUNCTION table_name_sunitest118(
tbl character varying)
RETURNS TABLE(column_name text)
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
RETURN QUERY
EXECUTE FORMAT('SELECT column_name FROM information_schema.columns where table_name=$1')
using tbl;
END
$BODY$;
In general you can use pg_typeof() to get that information:
select pg_typeof(column_name) from information_schema.columns limit 1;
┌───────────────────────────────────┐
│ pg_typeof │
├───────────────────────────────────┤
│ information_schema.sql_identifier │
└───────────────────────────────────┘
(1 row)
The type is sql_identifier, and you can cast it to text with column_name::text in your function.
CREATE OR REPLACE FUNCTION table_name_sunitest118(
tbl character varying)
RETURNS TABLE(column_name text)
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
RETURN QUERY
EXECUTE FORMAT(
'SELECT column_name::text FROM information_schema.columns where table_name=$1'
) using tbl;
END
$BODY$;
CREATE FUNCTION
select * from table_name_sunitest118('users');
┌─────────────┐
│ column_name │
├─────────────┤
│ email │
│ pass │
│ role │
│ id │
│ email │
└─────────────┘
(5 rows)
In MySQL, describe information_schema.columns says varchar(64).
The Postgres docs for the columns table says it is a sql_identifier defined as...
A character string. This type is used for SQL identifiers, the type character_data is used for any other kind of text data.
In psql you can use \gdesc command. It shows type on client side.
postgres=# select column_name from information_schema.columns \gdesc
┌─────────────┬──────┐
│ Column │ Type │
╞═════════════╪══════╡
│ column_name │ name │
└─────────────┴──────┘
(1 row)
pg_typeof function shows type on server side
postgres=# select pg_typeof(column_name) from information_schema.columns limit 1;
┌───────────────────────────────────┐
│ pg_typeof │
╞═══════════════════════════════════╡
│ information_schema.sql_identifier │
└───────────────────────────────────┘
(1 row)
could you please let me know, how can i get the function executed client(single client only) details inside the PL/pgSQL function(something $whoexecuted). i'm getting the current all active client details.
as per the following code.
begin
select ps.usename, ps.client_addr,ps.application_name from pg_stat_activity ps
where state = 'active'
and ps.usename in('user1') into pg_stat_activity_rowtype
;
The content of pg_stat_activity is available from PLpgSQL too. So you can use
do $$
declare r record;
begin
for r in select * from pg_stat_activity where pid = pg_backend_pid()
loop
raise notice '%', r;
end loop;
end;
$$;
These data can be collected from some source:
select current_user, session_user, current_database(), inet_client_addr(), current_setting('application_name');
┌──────────────┬──────────────┬──────────────────┬──────────────────┬─────────────────┐
│ current_user │ session_user │ current_database │ inet_client_addr │ current_setting │
╞══════════════╪══════════════╪══════════════════╪══════════════════╪═════════════════╡
│ pavel │ pavel │ postgres │ │ psql │
└──────────────┴──────────────┴──────────────────┴──────────────────┴─────────────────┘
(1 row)
More in documentation:
https://www.postgresql.org/docs/current/static/functions-admin.html
https://www.postgresql.org/docs/current/static/functions-info.html
I have the following function:
CREATE OR REPLACE FUNCTION public.get_string(cmd_type text, udf_name text,
group_name character varying DEFAULT 'usage'::character varying)
RETURNS text
LANGUAGE plpgsql
AS $function$
BEGIN
return 'This is the string: '''|| group_name ||''''::text;
END;
$function$
When i call it like this:
select public.get_string('test', 'myudf!', group_name=>null::character varying);
It returns NULL.
I expect it to at least return:
This is the string: ''
However, when I call it like this:
select public.get_string('test', 'myudf!');
The I get the expected:
This is the string: 'usage'
Why does passing NULL to an optional parameter make the entire string NULL?
It is not mystic - any operation over NULL value is NULL again.
postgres=# select ('Hello' || null) is null ;
┌──────────┐
│ ?column? │
╞══════════╡
│ t │
└──────────┘
(1 row)
You should to use a coalesce function and sanitize expression against NULL value.
postgres=# select ('Hello' || coalesce(null,'')) ;
┌──────────┐
│ ?column? │
╞══════════╡
│ Hello │
└──────────┘
(1 row)
Maybe you know a Oracle database, where NULL and empty strings are equal. But it is true only for Oracle, elsewhere NULL is NULL and it is more aggressive.
I have a Table "A" with one column "col1" where each record is a array of integers.
col1
-----
{1,2,3,4}
{1,2,6,7}
{1,2,3,8,9}
I like to have one row as result which contains the overlap or intersect of all arrays in "col1".
select overlap(col1) from A;
result
-----
{1,2}
You should to define custom aggregate for this purpose:
CREATE OR REPLACE FUNCTION public.overlap_array_aggregate(anyarray, anyarray)
RETURNS anyarray
LANGUAGE plpgsql STRICT
AS $function$
BEGIN
RETURN ARRAY(SELECT unnest($1) INTERSECT SELECT unnest($2));
END;
$function$
CREATE AGGREGATE array_overlap_agg (
basetype = anyarray,
sfunc = overlap_array_aggregate,
stype = anyarray );
Then it is working as you expect:
postgres=# SELECT * FROM foo;
┌─────────────┐
│ a │
╞═════════════╡
│ {1,2,3,4} │
│ {1,2,6,7} │
│ {1,2,3,8,9} │
└─────────────┘
(3 rows)
postgres=# SELECT array_overlap_agg(a) FROM foo;
┌───────────────────┐
│ array_overlap_agg │
╞═══════════════════╡
│ {1,2} │
└───────────────────┘
(1 row)