my query in postgresql 9.3 is:
SELECT *
FROM route
WHERE 'my/uri/address' LIKE CONCAT(c_uri, '%')
But in postgresql 8.4 this code not working.
How can i resolve, please?
Thanks in advance!
In PostgreSQL version 8.4 to String concatenation use || operation.
Example:'Post' || 'greSQL'
Result is: PostgreSQL
You could also use WS_CONCAT function but it is not defined in 8.4. You can declare it as the following:
CREATE OR REPLACE FUNCTION concat_ws(
separator text,
VARIADIC names_array text[]
)
RETURNS text
LANGUAGE plpgsql
AS $$
BEGIN
RETURN array_to_string(array_remove(names_array, NULL), ' ');
END;
$$;
This definition works exactly as in 9.x and above: pass the separator text first and then an arbitrary amount of texts to concat. NULL values get filtered out.
Example:
SELECT WS_CONCAT(' ', 'Ford', 'Focus', NULL /* Missing body-style */, '1.8 L')
Result: Ford Focus 1.8 L
Related
May I know on how to call an array in stored procedure? I tried to enclosed it with a bracket to put the column_name that need to be insert in the new table.
CREATE OR REPLACE PROCEDURE data_versioning_nonull(new_table_name VARCHAR(100),column_name VARCHAR(100)[], current_table_name VARCHAR(100))
language plpgsql
as $$
BEGIN
EXECUTE ('CREATE TABLE ' || quote_ident(new_table_name) || ' AS SELECT ' || quote_ident(column_name) || ' FROM ' || quote_ident(current_table_name));
END $$;
CALL data_versioning_nonull('sales_2019_sample', ['orderid', 'product', 'address'], 'sales_2019');
Using execute format() lets you replace all the quote_ident() with %I placeholders in a single text instead of a series of concatenated snippets. %1$I lets you re-use the first argument.
It's best if you use ARRAY['a','b','c']::VARCHAR(100)[] to explicitly make it an array of your desired type. '{"a","b","c"}'::VARCHAR(100)[] works too.
You'll need to convert the array into a list of columns some other way, because when cast to text, it'll get curly braces which are not allowed in the column list syntax. Demo
It's not a good practice to introduce random limitations - PostgreSQL doesn't limit identifier lengths to 100 characters, so you don't have to either. The default limit is 63 bytes, so you can go way, way longer than 100 characters (demo). You can switch that data type to a regular text. Interestingly, exceeding specified varchar length would just convert it to unlimited varchar, making it just syntax noise.
DBFiddle online demo
CREATE TABLE sales_2019(orderid INT,product INT,address INT);
CREATE OR REPLACE PROCEDURE data_versioning_nonull(
new_table_name TEXT,
column_names TEXT[],
current_table_name TEXT)
LANGUAGE plpgsql AS $$
DECLARE
list_of_columns_as_quoted_identifiers TEXT;
BEGIN
SELECT string_agg(quote_ident(name),',')
INTO list_of_columns_as_quoted_identifiers
FROM unnest(column_names) name;
EXECUTE format('CREATE TABLE %1$I.%2$I AS SELECT %3$s FROM %1$I.%4$I',
current_schema(),
new_table_name,
list_of_columns_as_quoted_identifiers,
current_table_name);
END $$;
CALL data_versioning_nonull(
'sales_2019_sample',
ARRAY['orderid', 'product', 'address']::text[],
'sales_2019');
Schema awareness: currently the procedure creates the new table in the default schema, based on a table in that same default schema - above I made it explicit, but that's what it would do without the current_schema() calls anyway. You could add new_table_schema and current_table_schema parameters and if most of the time you don't expect them to be used, you can hide them behind procedure overloads for convenience, using current_schema() to keep the implicit behaviour. Demo
First, change your stored procedure to convert selected columns from array to csv like this.
CREATE OR REPLACE PROCEDURE data_versioning_nonull(new_table_name VARCHAR(100),column_name VARCHAR(100)[], current_table_name VARCHAR(100))
language plpgsql
as $$
BEGIN
EXECUTE ('CREATE TABLE ' || quote_ident(new_table_name) || ' AS SELECT ' || array_to_string(column_name, ',') || ' FROM ' || quote_ident(current_table_name));
END $$;
Then call it as:
CALL data_versioning_nonull('sales_2019_sample', '{"orderid", "product", "address"}', 'sales_2019');
I am writing 1 PostgreSQL function for some operation.
Writing SQL migration for that function but facing formatting error as liquibase is not able to recognize some portion.
Function Liquibase Migration:
CREATE OR REPLACE FUNCTION schema.fncn(trId integer, sts integer, stIds character varying)
RETURNS double precision
LANGUAGE plpgsql
AS '
DECLARE
abc integer;
query CHAR(1500);
xyz integer;
BEGIN
query := ''select sum(t.a)
FROM schema.tbl t
where t.id in(1,2)
and t.status ='' || sts ||
'' and t.status <> 2
and t.tr_id ='' || trId ||
'' and t.sw in('''', ''N'')'';
IF stIds is not null then
query := query || '' AND t.st_id IN ('' || stIds || '')'';
ELSE
END IF;
EXECUTE query INTO abc;
SELECT abc INTO xyz;
RETURN xyz;
END;
'
;
Following error it throwing:
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "N"
Reason: liquibase.exception.DatabaseException: ERROR: syntax error at or near "N"
Any suggestion what I am missing?
The immediate problem is the nesting of ' of single quotes. To make that easier, use dollar quoting for the function body. You can nest dollar quoted string by choosing different delimiters.
To avoid any problems with concatenation of parameters, use parameter place holders in the query and pass the values with the USING clause. That will however require two different execute calls.
I assume stIds is a comma separated string of values. To use that as a (single) placeholder, convert it to an array using string_to_array() - or even better: change the type of the input parameter to text[] and pass an array directly.
The query variable is better defined as text, don't use char. There is also no need to copy the result of the query into a different variable (which by the way would be more efficient using xyz := abc; rather than a select into)
CREATE OR REPLACE FUNCTION schema.fncn(trId integer, sts integer, stIds character varying)
RETURNS double precision
LANGUAGE plpgsql
AS
$body$
DECLARE
abc integer;
query text;
BEGIN
query := $q$ select sum(t.a)
FROM schema.tbl t
where t.id in (1,2)
and t.status = $1
and t.status <> 2
and t.tr_id = $2
and t.sw in ('''', 'N') $q$;
IF stIds is not null then
query := query || $sql$ AND t.st_id = ANY (string_to_array($4, ',') $sql$;
EXECUTE query INTO abc
using trid, sts, stids;
ELSE
EXECUTE query INTO abc
using trid, sts;
END IF;
RETURN abc;
END;
$body$
;
Note that in the Liquibase change, you must use splitStatements=false in order to run this without errors.
Given an arbitrary PostgreSQL query, e.g. SELECT * FROM (...) AS T, how can I get resultset column names and types WITHOUT actually executing the query using psycopg2 Python3 library?
I saw JDBC solution using getMetaData(), but I cannot figure out how to get that same information in psycopg2.
PreparedStatement pstmt = con.prepareStatement("select ... ");
ResultSetMetaData meta = pstmt.getMetaData();
for (int i=1; i <= meta.getColumnCount(); i++) { ... }
As far as I understand, that's not possible without executing(running cur.execute())
But, If you want a Postgres solution using a function that can be used by Psycopg2 as a query, you may use this solution. As you were expecting, this will not execute your query, it simply creates a temporary View which allows us to query it's metadata using the catalog information_schema.columns
CREATE OR REPLACE function define_query(query text)
RETURNS TABLE( column_name text,data_type text)
LANGUAGE plpgsql AS
$$
DECLARE
v_view_n TEXT := 'temp_view$';
BEGIN
EXECUTE format( 'CREATE OR REPLACE TEMP VIEW %I AS %s', v_view_n,query);
RETURN QUERY select i.column_name::text, i.data_type ::text
from information_schema.columns i where i.table_name = v_view_n;
END $$;
Once you've got this function, you can get the definition of any query by simply calling this function and not executing it.
knayak=# select * from define_query('select 1::int as a,''TWO''::text as b');
column_name | data_type
-------------+-----------
a | integer
b | text
(2 rows)
I think you have to execute something at least.
If you don't want any rows returned, you can query like select * from XXX where false. This query will return types of columns to client with 0 rows.
How to create GUID in Windows format in Postgres 9.0+?
I tried function
CREATE or REPLACE FUNCTION public.getguid() RETURNS varchar AS $BODY$
DECLARE
v_seed_value varchar(32);
BEGIN
select
md5(
inet_client_addr()::varchar ||
timeofday() ||
inet_server_addr()::varchar ||
to_hex(inet_client_port())
)
into v_seed_value;
return (substr(v_seed_value,1,8) || '-' ||
substr(v_seed_value,9,4) || '-' ||
substr(v_seed_value,13,4) || '-' ||
substr(v_seed_value,17,4) || '-' ||
substr(v_seed_value,21,12));
END; $BODY$ LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
from
http://postgresql.1045698.n5.nabble.com/newid-in-postgres-td1879346.html
Tried
select getguid()
union all
select getguid()
but it returns same values
"c41121ed-b6fb-c9a6-bc9b-574c82929e7e"
"c41121ed-b6fb-c9a6-bc9b-574c82929e7e"
How to fix this so that unique rows are returned?
PostgreSQL has the uuid-ossp extension which ships with the standard distributions and it has 5 standard algorithms for generating uuids. Note that a guid is the Microsoft version of a uuid, conceptually they are the same thing.
CREATE EXTENSION "uuid-ossp";
Then:
SELECT uuid_generate_v4();
Note also that, once you installed the extension, PostgreSQL has an actual binary uuid type, with a length of 16 bytes. Working with the binary type is much faster than working with the text equivalent and it takes up less space. If you do need the string version, you can simply cast it to text:
SELECT uuid_generate_v4()::text;
PostgreSQL 13+
You can now use the built-in function gen_random_uuid() to get a version 4 random UUID.
I am trying to create an aggregate function that concatenates numbers by grouping them. How can I go about it? Let's say I have a table like this below.
Table Numbers
123
145
187
105
I want the outcome to look like
105_123_145_187
I know how to use group_concat separator _ if I am working in MySQL.
How can I do it in PostgreSQL?
There is already such function:
SELECT string_agg(num::text,'_')
FROM Numbers;
Details here: string_agg.
Tell me, if you use postgresql 8.4 or earlier version. I will show you, how to implement this function as custom aggregate.
UPD Custom aggregate:
CREATE OR REPLACE FUNCTION public.concat_delimited (text, text, text)
RETURNS text AS
$body$
SELECT $1 || (CASE WHEN $1 = '' THEN '' ELSE $3 END) || $2;
$body$
LANGUAGE 'sql'
IMMUTABLE
RETURNS NULL ON NULL INPUT;
CREATE AGGREGATE public.text_concat (text, text)
(
SFUNC = public.concat_delimited,
STYPE = text
);
For modern PostgreSQL use string_agg(columnname,'_').
For old versions 8.4 and up, use string_to_array(array_agg(columname), '_')
See the array functions and operators documentation.
Example:
regress=> SELECT array_to_string(array_agg(x::text), ', ') FROM generate_series(1,10) x;
array_to_string
-------------------------------
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1 row)
Always include your PostgreSQL version in your questions.
concat_ws(sep text, str "any" [, str "any" [, ...] ]) is the function your looking for.
The first param is your separator, NULL args are ignored. See The PostgreSQL manual for details.
I am not versed in pgSQL at all, but the answer for writing an aggregate function is going to lay there, check out the pgSQL manual for how to write your functions.