What the parameters before brackets mean? - pact-lang

In the documentation you can insert data inside a table with the following syntax:
(insert table-name id {"parameter":parameterValue})
But here, in this example i have extra values in parameters before the brackets.
(insert loans-inventory (inventory-key loanId entityName) {"balance":loanAmount})
What (inventorty-key loanId and entintynName) syntax mean? (inventory-key) is a function.
inventory-key function
(defun inventory-key (loanId:string owner:string)
(format "{}:{}" [loanId owner]))

(inventory-key loanId entityName) is a call to the inventory-key function with loanId and entityName as arguments. It all returns a value that serves the purpose as a key to the row that is being inserted in the table.
The key used comes from the output of the inventory-key function, which looking at the example (loans tutorial) it is a function that returns a string in the format of loanId:owner, probably to make it unique.

Related

extracting certain size data from column

I have a table in MS SQL Server 2016. the table has a column called notes varchar(255)
The data that contains in the notes column contains notes entry by end user.
Select ServiceDate, notes from my_table
ServiceDate, notes
--------------------------------------
9/1/2022 The order was called in AB13456736
9/1/2022 AB45876453 not setup
9/2/2022 Signature for AB764538334
9/2/2022 Contact for A0943847432
9/3/2022 Hold off on AB73645298
9/5/2022 ** Confirmed AB88988476
9/6/2022 /AB9847654 completed
I would like to be able to extract the word AB% from the notes column. I know the ABxxxxxxx is always 10 characters. Because the ABxxxxxx always entered in different position, it's difficult to use exact extract where to look for. I have tried substring(), left() functions and because the value AB% is always in different positions, I can't get it to extract. is there a method I can use to do this?
thanks in advance.
Assuming there is only ONE AB{string} in notes, otherwise you would need a Table-Valued Function.
Note the nullif(). This is essentially a Fail-Safe if the string does not exist.
Example
Declare #YourTable Table ([ServiceDate] varchar(50),[notes] varchar(50)) Insert Into #YourTable Values
('9/1/2022','The order was called in AB13456736')
,('9/1/2022','AB45876453 not setup')
,('9/2/2022','Signature for AB764538334')
,('9/2/2022','Contact for A0943847432')
,('9/3/2022','Hold off on AB73645298')
,('9/5/2022','** Confirmed AB88988476')
,('9/6/2022','/AB9847654 completed')
Select *
,ABValue = substring(notes,nullif(patindex('%AB[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%',notes),0),10)
from #YourTable
Results
ServiceDate notes ABValue
9/1/2022 The order was called in AB13456736 AB13456736
9/1/2022 AB45876453 not setup AB45876453
9/2/2022 Signature for AB764538334 AB76453833
9/2/2022 Contact for A0943847432 NULL
9/3/2022 Hold off on AB73645298 AB73645298
9/5/2022 ** Confirmed AB88988476 AB88988476
9/6/2022 /AB9847654 completed NULL

Is it possible to add a constraint to check every inserted object into a JSON array using Postgres?

I am trying to figure out how to add a constraint to my table that contains a JSON object in Postgres. I would like that constraint to make sure a jpg will have a non null md5 property.
I have tried to check the subarray but I cannot get it to work on an array. I can test the property if use the dereferencing arrow operator (table->'jpg'->0 ? 'md5'). I have tried to use the jsonb_array_elements() function as well but it is not allowed inside a constraint statement.
For instance:
{
jpg: [
{
md5: "some md5",
...
}
]
}
I would use this:
ALTER TABLE table ADD CONSTRAINT md5_is_defined CHECK(table->'jpg'->0 ? 'md5')
But I don't want to check just the first inserted element
I would like to know if there is some trick to use jsonb_array_elements in this check statement. And yes I realize I should normalize my data. I tried to do this but it became a monstrosity to write the statements for.
Arrays are extremely cumbersome to deal with in SQL as they basically violate anything that SQL does. Checking every element in an array for the presence of something is typically a strong indication that an array was the wrong choice to begin with.
With Postgres 12 this is extremely easy to do:
alter table the_table
add constraint md5_is_defined
check (jsonb_path_exists(the_column, '$.jpg[*].md5'));
For older versions, the only thing I can think of is to create a function that checks the presence and then use that function in the check constraint:
create or replace function check_md5(p_input jsonb)
returns boolean
as
$$
select exists (select *
from jsonb_array_elements(p_input -> 'jpg') as t(e)
where e ? 'md5');
$$
language sql
immutable;
Then you can use it like this:
alter table the_table
add constraint md5_is_defined
check (check_md5(the_column));
Edit
To check if a specific key contains a non-empty array you can use something like this:
alter table the_table
add constraint non_empty_array
check (jsonb_path_exists(the_column, '$.event ? (#.teams.type() == "array" && #.teams.size() > 0)'));
The check for #.teams.type() == "array" is necessary because a simple {"teams": "yes"} also returns a non-zero value for size()

Error when trying to find ANY of int array

I'm currently working on a function in PostgreSQL, where it takes in an array of integers. Everything in the function is working as expected, however at one point in the function I do the following:
EXECUTE
'INSERT INTO tmptable (user_id)
SELECT DISTINCT user_id FROM user_skills
WHERE skill_values_id=ANY('||selected_skills||')';
My function is able to read the array at other points in the code, however this part throws the following error:
Procedure execution failed
ERROR: malformed array literal: "
INSERT INTO tmptable (user_id)
SELECT DISTINCT user_id FROM user_skills
WHERE skill_values_id=ANY("
And finally- there is a line at the bottom of the error message that says:
DETAIL: Array value must start with "{" or dimension information.
Any ideas how to get the any and integer array to play nice? I'm assuming it has something to do with the || concentration casting it to a string?
Don't concatenate values, use parameters instead:
EXECUTE
'INSERT INTO tmptable (user_id)
SELECT DISTINCT user_id FROM user_skills
WHERE skill_values_id=ANY($1)'
using selected_skills;
More details in the manual:
https://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN

Postgres function with jsonb parameters

I have seen a similar post here but my situation is slightly different from anything I've found so far. I am trying to call a postgres function with parameters that I can leverage in the function logic as they pertain to the jsonb query. Here is an example of the query I'm trying to recreate with parameters.
SELECT *
from edit_data
where ( "json_field"#>'{Attributes}' )::jsonb #>
'{"issue_description":"**my description**",
"reporter_email":"**user#generic.com**"}'::jsonb
I can run this query just fine in PGAdmin but all my attempts thus far to run this inside a function with parameters for "my description" and "user#generic.com" values have failed. Here is a simple example of the function I'm trying to create:
CREATE OR REPLACE FUNCTION get_Features(
p1 character varying,
p2 character varying)
RETURNS SETOF edit_metadata AS
$BODY$
SELECT * from edit_metadata where ("geo_json"#>'{Attributes}' )::jsonb #> '{"issue_description":**$p1**, "reporter_email":**$p2**}'::jsonb;
$BODY$
LANGUAGE sql VOLATILE
COST 100
ROWS 1000;
I know that the syntax is incorrect and I've been struggling with this for a day or two. Can anyone help me understand how to best deal with these double quotes around the value and leverage a parameter here?
TIA
You could use function json_build_object:
select json_build_object(
'issue_description', '**my description**',
'reporter_email', '**user#generic.com**');
And you get:
json_build_object
-----------------------------------------------------------------------------------------
{"issue_description" : "**my description**", "reporter_email" : "**user#generic.com**"}
(1 row)
That way there's no way you will input invalid syntax (no hassle with quoting strings) and you can swap the values with parameters.

Unnest multiple arrays in parallel

My last question Passing an array to stored to postgres was a bit unclear. Now, to clarify my objective:
I want to create an Postgres stored procedure which will accept two input parameters. One will be a list of some amounts like for instance (100, 40.5, 76) and the other one will be list of some invoices ('01-2222-05','01-3333-04','01-4444-08'). After that I want to use these two lists of numbers and characters and do something with them. For example I want to take each amount from this array of numbers and assign it to corresponding invoice.
Something like that in Oracle would look like this:
SOME_PACKAGE.SOME_PROCEDURE (
789,
SYSDATE,
SIMPLEARRAYTYPE ('01-2222-05','01-3333-04','01-4444-08'),
NUMBER_TABLE (100,40.5,76),
'EUR',
1,
P_CODE,
P_MESSAGE);
Of course, the two types SIMPLEARRAYTYPE and NUMBER_TABLE are defined earlier in DB.
You will love this new feature of Postgres 9.4:
unnest(anyarray, anyarray [, ...])
unnest() with the much anticipated (at least by me) capability to unnest multiple arrays in parallel cleanly. The manual:
expand multiple arrays (possibly of different types) to a set of rows. This is only allowed in the FROM clause;
It's a special implementation of the new ROWS FROM feature.
Your function can now just be:
CREATE OR REPLACE FUNCTION multi_unnest(_some_id int
, _amounts numeric[]
, _invoices text[])
RETURNS TABLE (some_id int, amount numeric, invoice text) AS
$func$
SELECT _some_id, u.* FROM unnest(_amounts, _invoices) u;
$func$ LANGUAGE sql;
Call:
SELECT * FROM multi_unnest(123, '{100, 40.5, 76}'::numeric[]
, '{01-2222-05,01-3333-04,01-4444-08}'::text[]);
Of course, the simple form can be replaced with plain SQL (no additional function):
SELECT 123 AS some_id, *
FROM unnest('{100, 40.5, 76}'::numeric[]
, '{01-2222-05,01-3333-04,01-4444-08}'::text[]) AS u(amount, invoice);
In earlier versions (Postgres 9.3-), you can use the less elegant and less safe form:
SELECT 123 AS some_id
, unnest('{100, 40.5, 76}'::numeric[]) AS amount
, unnest('{01-2222-05,01-3333-04,01-4444-08}'::text[]) AS invoice;
Caveats of the old shorthand form: besides being non-standard to have set-returning function in the SELECT list, the number of rows returned would be the lowest common multiple of each arrays number of elements (with surprising results for unequal numbers). Details in these related answers:
Parallel unnest() and sort order in PostgreSQL
Is there something like a zip() function in PostgreSQL that combines two arrays?
This behavior has finally been sanitized with Postgres 10. Multiple set-returning functions in the SELECT list produce rows in "lock-step" now. See:
What is the expected behaviour for multiple set-returning functions in SELECT clause?
Arrays are declared by adding [] to the base datatype. You declare them as a parameter the same way you declare regular parameters:
The following function accepts an array of integers and and array of strings and will return some dummy text:
create function array_demo(p_data integer[], p_invoices text[])
returns text
as
$$
select p_data[1] || ' => ' || p_invoices[1];
$$
language sql;
select array_demo(array[1,2,3], array['one', 'two', 'three']);
SQLFiddle demo: http://sqlfiddle.com/#!15/fdb8d/1

Resources