update vachar column to date in postgreSQL - postgresql

Trying to update a column with varchar datatype e.g. '1950-08-14' to a date datatype using
UPDATE tablename SET columnname = to_date(columnname, 'YYYY-MM-DD');
or
ALTER TABLE tablename ALTER COLUMN columnname TYPE DATE USING to_date(columnname, 'YYYY-MM-DD');
but both return the error message
ERROR: invalid value "columnname" for "YYYY"
DETAIL: Value must be an integer.
Referencing http://www.postgresql.org/docs/9.4/static/functions-formatting.html

The query:
ALTER TABLE tablename
ALTER COLUMN columnname TYPE DATE USING to_date(columnname, 'YYYY-MM-DD');
is correct.
The error message means that you have invalid value in column columnname (actualy the invalid value is 'columnname').
All the values in the column must have the format 'YYYY-MM-DD', e.g. '2015-01-01' (or be null).
Solution with a new column.
Create a function to convert varchar to date which returns null for invalid values:
create or replace function varchar_to_date_or_null(str varchar)
returns date language plpgsql as $$
begin
return to_date(str, 'YYYY-MM-DD');
exception
when invalid_datetime_format then return null;
end $$;
Add a new column and update it using the function:
alter table tablename add new_column date;
update tablename
set new_column = varchar_to_date_or_null(columnname);

Related

PostgreSQL - How to handle invalid values when casting to timestamp in SELECT from jsonb data

I am trying to get data from a jsonb column and need to cast an attribute from the payload to timestamp. But the query aborts when the value is null or invalid.
This is my select statement.
Select
(jsonb_path_query(AnchorNode, '$.TestDate')#>> '{}')::timestamp as TestDate
From (
Select
jsonb_path_query_first(payload, '$.node1[*].node2[*]') as AnchorNode
From TestTable
) subq1
The invalid values could be only the Date or null.
How can I change the query to handle this. There are about 7 or 8 date fields where I would need to do this
Thank you
Maybie try to cast text inside a function and return null on exception
create or replace function str_to_timestamp(_date text) returns timestamp
language plpgsql AS
$$
BEGIN
return _date::timestamp;
EXCEPTION WHEN OTHERS THEN
return null::timestamp;
END;
$$;
It was possible to achieve above using CASE statement. It may also be done using COALESCE
Select
case
when jsonb_typeof(AnchorNode -> 'TestDate') is null then null
when jsonb_typeof(AnchorNode -> 'TestDate') = 'string' then (AnchorNode ->> 'TestDate')::timestamp
end TestDateTS,
From (
Select
jsonb_path_query_first(payload, '$.node1[*].node2[*]') as AnchorNode
From TestTable
) subq1
OR
COALESCE((AnchorNode ->> 'TestDate')::timestamp, null) as "TestDate"

Postgresql - Returned type record does not match expected type uuid

I have very simple function that should return few rows including the uuid type as the first column.
Function:
CREATE OR REPLACE FUNCTION public.export_wizard()
RETURNS TABLE(id uuid, my_column text)
LANGUAGE plpgsql
AS $function$
BEGIN
return query select (w.id, w.my_column) from wizard w;
END;
$function$
;
Table (short version):
CREATE TABLE IF NOT EXISTS public.wizard
(
id uuid NOT NULL,
my_column text COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT wizard_pkey PRIMARY KEY (id)
)
After calling the function like this: select * from export_wizard();
I got an error:
SQL Error [42804]: ERROR: structure of query does not match function result type
Detail: Returned type record does not match expected type uuid in column 1.
Where: PL/pgSQL function export_wizard() line 3 at RETURN QUERY
Thanks for any advices.
I made terrible mistake by adding (no idea why) brackets in SELECT statement as mentioned by #Adrian Klaver.
Correct: return query select w.id, w.my_column from wizard w;

Postgres date value dynamic inserting

I am scratching my head trying to fix the following:
create or replace procedure my_schema.Test()
as $$
declare
today date = now();
begin
drop table if exists my_schema.tst_table;
create table my_schema.tst_table (
todays_date varchar );
execute('
insert into my_schema.tst_table
values (' || today || ')
');
end;
$$
language plpgsql;
Basically I am trying to dynamically insert the current date into a table which will be used in later steps.
The issue I am facing is that due to the today variable looking like '2022-02-11', and because I am inserting the record dynamically, postgres is interpreting the "-" as a minus sign and inserting the value 2009 into my table.
Does anyone have a workaround for this?
Don't concatenate input values into dynamic SQL. And never store date values in a varchar column:
create or replace procedure my_schema.Test()
as $$
declare
today date := current_date;
begin
drop table if exists my_schema.tst_table;
create table my_schema.tst_table
(
todays_date date
);
execute('
insert into my_schema.tst_table
values ($1)
') using today;
end;
$$
language plpgsql;
But creating a table just to store the value of current_date seems a bit of an overkill.
You can use the cast operator to force the value conversion to VARCHAR datatype:
execute('
insert into my_schema.tst_table
values ('today'::VARCHAR)
');

How to use JSONB_SET for updating JSONB Column in PostgreSQL Procedure

I am using a Stored Procedure to update a JSONB column in the table and it does not seem to work. Any help would be much appreciated. Many Thanks.
My Table is:
CREATE TABLE mn_customer (
cust_id int,
f_name varchar(20),
l_name varchar(20),
json_payload jsonb);
My SPROC is:
create or replace procedure update_mn_customer
(
update_cust_id int DEFAULT null,
update_json_payload jsonb DEFAULT null
)
language plpgsql as
$proc$
begin
update mn_customer
set json_payload = jsonb_set(json_payload, update_json_payload)
where cust_id = update_cust_id;
commit;
end
$proc$;
My call to procedure to perform an Update is:
call update_mn_customer(
1998, to_jsonb('{"jsonpayload-fld1": "John Davis", "jsonpayload-fld2": "Lenny Pascoe","jsonpayload-fld3": "Undefined"}'::text)
);
I keep getting the Error:
ERROR: function jsonb_set(jsonb, jsonb) does not exist
LINE 2: set json_payload = jsonb_set(json_payload, update_js...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
QUERY: update mn_customer
set json_payload = jsonb_set(json_payload, update_json_payload)
where cust_id = update_cust_id
CONTEXT: PL/pgSQL function update_mn_customer(integer,jsonb) line 8 at SQL statement
You use jsonb_set when you want to replace only one part of the jsonb data identified by a path with a new jsonb value. In your case, it seems that update_json_payload is the new value for the json_payload column so you just have to update it :
update mn_customer
set json_payload = update_json_payload
where cust_id = update_cust_id ;
Then you don't need to commit inside the plpgsql procedure.

Ambiguous column reference - it could refer to either a PL/pgSQL variable or a table column?

I am getting the following error in PostgreSQL:
[42702] ERROR: column reference "topicid" is ambiguous Detail: It
could refer to either a PL/pgSQL variable or a table column. Where:
PL/pgSQL function topics(integer) line 3 at RETURN QUERY
I understand that to mean there is a parameter and a table column with the same name. Except that I cannot see where it is because the only parameter I have is _typeid and not topicid.
Where is the problem exactly in this function:
CREATE FUNCTION topics(_typeid integer DEFAULT NULL::integer)
RETURNS TABLE(topicid integer, typeid integer, topic character varying)
LANGUAGE plpgsql
AS
$$
BEGIN
RETURN QUERY SELECT
topicid
,typeid
,topic
FROM
topic
WHERE
_typeid IS NULL
OR
typeID = _typeid
ORDER BY
topic ASC;
END
$$;
If I refactor it to just use sql then it works fine like such:
CREATE FUNCTION topics(_typeid integer DEFAULT NULL::integer)
RETURNS TABLE(topicid integer, typeid integer, topic character varying)
LANGUAGE sql
AS
$$
SELECT
topicid
,typeid
,topic
FROM
topic
WHERE
_typeid IS NULL
OR
typeID = _typeid
ORDER BY
topic ASC;
$$;
The conflict is between the variables in RETURNS TABLE and the field names returned from the query. Table qualify the field names in the query e.g. topic.topicid, topic.typid, topic.topic.