I have a sensor data table full of 'holes', the data is only saved when it changes over an specified threshold.
| time stamp | value1 | value2 |
| 2012-01-01 | 1 | |
| 2012-01-02 | | 2 |
| 2012-01-05 | | |
| 2012-01-20 | | |
| 2012-03-01 | 3 | 1 |
I need to do cross row calculations, but the holes in the tables make it impractical. My solution was to create an auxiliary function to wrap up the related field, and use session parameter as a persistent variable. sth like this:
CREATE FUNCTION wrap_data( data1 numeric(3,1) )
... LANGUAGE plpgsql
IF data1 <> NULL THEN
EXECUTE 'SET SESSION app.data1 = $1;' USING data1;
END IF;
RETURN current_setting('app.data1')::numeric(3,1)
...
It works but before executing the function, I always have to initialized the variables outside of the function by:
SET SESSION app.data1 = 11.1;
Or it will complain parameter not unrecognized.
I am looking for a function like IfParameterExist(), which allow me to check the existence of this variable without raising error inside my plpgsql function.
Related
I have 3 tables.
Table 'number':
| x |
|---|
| 1 |
| 2 |
| 3 |
Table 'group':
| group_id |
|----------|
| 1 |
| 2 |
Table 'number_in_group':
| group_id | x |
|----------|---|
| 1 | 4 |
| 1 | 5 |
| 2 | 4 |
| 2 | 5 |
| 2 | 7 |
Could I make a constraint on inserting into table number_in_group that x does not exist in table number?
If yes, is it a good approach, or better to put this business logic on the backend?
There is no constraint in Postgres that say make sure something does not exist, but you can create one - a trigger. In this case you select from numbers for the new value of x in number_in_group. If it exists then raise an exception. (see demo)
create or replace function not_if_in_numbers()
returns trigger
language plpgsql
as $$
begin
if exists
(select null
from numbers
where x = new.x
)
then
raise exception 'Invalid value for x (%). Found in numbers table.',new.x::text;
end if;
return new;
end;
$$;
create trigger check_restricted_x_biur
before insert or update of x
on number_in_group
for each row
execute function not_if_in_numbers();
You should create a similar trigger for numbers selecting from number_in_group and throws a corresponding exception. Do not build around the concept of an immutable table. It will not happen.
trying to delete records by passing arrays into the stored function.
testing=# select * from links;
id | url | name | description | last_update
----+------------------------------------+---------------------+-------------+-------------
1 | https://www.postgresqltutorial.com | PostgreSQL Tutorial | |
2 | http://www.oreilly.com | O'Reilly Media | |
7 | http://www.postgresql.org | PostgreSQL | |
8 | https://www.google.com | Google | | 2013-06-01
(4 rows)
My Function
CREATE OR REPLACE FUNCTION testing(TEXT[])
RETURNS INTEGER AS
$BODY$
DECLARE emp_id INTEGER;
BEGIN
SELECT id into emp_id from links e where name = ANY($1);
DELETE FROM links WHERE id = emp_id;
return emp_id;
END
$BODY$
LANGUAGE plpgsql;
Query to call function
SELECT * from testing(ARRAY['PostgreSQL','Google']::TEXT[]);
We pass two records to delete from the links table, But instead of that only one record is deleting.
testing=# select * from links;
id | url | name | description | last_update
----+------------------------------------+---------------------+-------------+-------------
1 | https://www.postgresqltutorial.com | PostgreSQL Tutorial | |
2 | http://www.oreilly.com | O'Reilly Media | |
7 | http://www.postgresql.org | PostgreSQL | |
(3 rows)
SELECT ... INTO only stores the first row in the variable and ignores the rest.
You should declare the function as RETURNS SETOF integer, omit the SELECT and run only the DELETE as detailed in my other answer. Then you can use an SQL function rather than a PL/pgSQL one, which will simplify everything.
I suspect this question is already well-answered but perhaps due to limited SQL vocabulary I have not managed to find what I need. I have a database with many code:description mappings in a single 'parameter' table. I would like to define a query or procedure to return the descriptions for all (or an arbitrary list of) coded values in a given 'content' table with their descriptions from the parameter table. I don't want to alter the original data, I just want to display friendly results.
Is there a standard way to do this?
Can it be accomplished with SELECT or are other statements required?
Here is a sample query for a single coded field:
SELECT TOP (5)
newid() as id,
B.BRIDGE_STATUS,
P.SHORTDESC
FROM
BRIDGE B
LEFT JOIN PARAMTRS P ON P.TABLE_NAME = 'BRIDGE'
AND P.FIELD_NAME = 'BRIDGE_STATUS'
AND P.PARMVALUE = B.BRIDGE_STATUS
ORDER BY
id
I want to produce 'decoded' results like:
| id | BRIDGE_STATUS |
|--------------------------------------|------------ |
| BABCEC1E-5FE2-46FA-9763-000131F2F688 | Active |
| 758F5201-4742-43C6-8550-000571875265 | Active |
| 5E51634C-4DD9-4B0A-BBF5-00087DF71C8B | Active |
| 0A4EA521-DE70-4D04-93B8-000CD12B7F55 | Inactive |
| 815C6C66-8995-4893-9A1B-000F00F839A4 | Proposed |
Rather than original, coded data like:
| id | BRIDGE_STATUS |
|--------------------------------------|---------------|
| F50214D7-F726-4996-9C0C-00021BD681A4 | 3 |
| 4F173E40-54DC-495E-9B84-000B446F09C3 | 3 |
| F9C216CD-0453-434B-AFA0-000C39EFA0FB | 3 |
| 5D09554E-201D-4208-A786-000C537759A1 | 1 |
| F0BDB9A4-E796-4786-8781-000FC60E200C | 4 |
but for an arbitrary number of columns.
Probably something dumb, but I just can't make it work.
I have this table:
Table "public.office"
Column | Type | Collation | Nullable | Default
-------------+--------------------------+-----------+----------+-------------------------------
id | integer | | not null | generated by default as identity
name | text | | not null |
url | text | | |
domain | text | | |
...
Triggers:
updated_save_domain_from_url AFTER UPDATE OF url ON office FOR EACH ROW EXECUTE PROCEDURE save_domain_from_url()
And this trigger function:
-- TRIGGER FUNCTION
CREATE OR REPLACE FUNCTION public.save_domain_from_url()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
BEGIN
new.domain := substring(new.url from '(?:.*://)?(?:www\.)?([^/]*)');
RETURN new;
END;
$function$
Example row:
id | name | url | domain
-----+---------------------------------+--------+--------
425 | Van Halewyck & Marco Architects | [NULL] | [NULL]
When I update the URL:
update office set url = 'http://vanhalewyck-marco.com/en' where id = 425;
The domain is still null, trigger did not work:
id | name | url | domain
-----+---------------------------------+---------------------------------+--------
425 | Van Halewyck & Marco Architects | http://vanhalewyck-marco.com/en | [NULL]
Any hints of what might be going on, please help!!
Thanks
You need to have the trigger defined as BEFORE trigger. AFTER triggers (as yours) cannot alter the new record as they are executed after the record is inserted.
Best regards,
Bjarni
I have a text column indicating date i.e. 20170101
UPDATE table_name
SET work_date = to_date(workdate, 'YYYYMMDD');
I used this command to convert it as date. However, I got a odd result. I read though other existing posts but not sure what's wrong here.
+----------+---------------+
| workdate | work_date |
+----------+---------------+
| 20170211 | 2207-05-09 |
| 20170930 | 2209-04-27 |
| 20170507 | 2208-02-29 |
| 20170318 | 2207-08-24 |
+----------+---------------+
I think you must be mistaken about the data you are supplying to to_date.
For example, input to these functions is not restricted by normal ranges, thus to_date('20096040','YYYYMMDD') returns 2014-01-17 rather than causing an error.
Source: https://www.postgresql.org/docs/9.6/static/functions-formatting.html