Best way to write a udf in vertica, where I need to refer to data from one of the rate table and write a formula on top - sql

I am planning to write a udf which can return the new value based on the rate setup for a specific date in a table, which means i need to write a query in udf
1. is it recommended as there are not enough example which refers to a table in udf
2. what are the other ways to solve this as Vetica procedural function does not allow to query within the function sql how it works in plsql

The requirement is not clear but a UDF function can be used. Below is the pseudocode
CREATE FUNCTION updateRate(x DATE) RETURN INT
AS BEGIN
RETURN (<your logic on updating rate> );
END;
And then call the function in update query
=>Update Mytable set rate=updateRate(colDate);

Related

How to use a temp sequence within a Postgresql function

I have some lines of SQL which will take a set of IDs from the same GROUP_ID that are not contiguous (ex. if some rows got deleted) and will make them contiguous again. I wanted to turn this into a function for reusability purposes. The lines work if executed individually but when I try to create the function I get the error
ERROR: relation "id_seq_temp" does not exist
LINE 10: UPDATE THINGS SET ID=nextval('id_se...
If I create a sequence outside of the function and use that sequence in the function instead then the function is created successfully (schema qualified or unqualified). However I felt like creating the temp sequence inside of the function rather than leaving it in the schema was a cleaner solution.
I have seen this question: Function shows error "relation my_table does not exist"
However, I'm using the public schema and schema qualifying the sequence with public. does not seem to help.
I've also seen this question: How to create a sql function using temp sequences and a SELECT on PostgreSQL8. I probably could use generate_series but this adds a lot of complexity that SERIES solves such as needing to know how big of a series to generate.
Here is my function, I anonymized some of the names - just in case there's a typo.
CREATE OR REPLACE FUNCTION reindex_ids(IN BIGINT) RETURNS VOID
LANGUAGE SQL
AS $$
CREATE TEMPORARY SEQUENCE id_seq_temp
MINVALUE 1
START WITH 1
INCREMENT BY 1;
ALTER SEQUENCE id_seq_temp RESTART;
UPDATE THINGS SET ID=ID+2000 WHERE GROUP_ID=$1;
UPDATE THINGS SET ID=nextval('id_seq_temp') WHERE GROUP_ID=$1;
$$;
Is it possible to use a sequence you create within a function later in the function?
Answer to question
The reason is that SQL functions (LANGUAGE sql) are parsed and planned as one. All objects used must exist before the function runs.
You can switch to PL/pgSQL, (LANGUAGE plpgsql) which plans each statement on demand. There you can create objects and use them in the next command.
See:
Why can PL/pgSQL functions have side effect, while SQL functions can't?
Since you are not returning anything, consider a PROCEDURE. (FUNCTION works, too.)
CREATE OR REPLACE PROCEDURE reindex_ids(IN bigint)
LANGUAGE plpgsql AS
$proc$
BEGIN
IF EXISTS ( SELECT FROM pg_catalog.pg_class
WHERE relname = 'id_seq_temp'
AND relnamespace = pg_my_temp_schema()
AND relkind = 'S') THEN
ALTER SEQUENCE id_seq_temp RESTART;
ELSE
CREATE TEMP SEQUENCE id_seq_temp;
END IF;
UPDATE things SET id = id + 2000 WHERE group_id = $1;
UPDATE things SET id = nextval('id_seq_temp') WHERE group_id = $1;
END
$proc$;
Call:
CALL reindex_ids(123);
This creates your temp sequence if it does not exist already.
If the sequence exists, it is reset. (Remember that temporary objects live for the duration of a session.)
In the unlikely event that some other object occupies the name, an exception is raised.
Alternative solutions
Solution 1
This usually works:
UPDATE things t
SET id = t1.new_id
FROM (
SELECT pk_id, row_number() OVER (ORDER BY id) AS new_id
FROM things
WHERE group_id = $1 -- your input here
) t1
WHERE t.pk_id = t1.pk_id;
And only updates each row once, so half the cost.
Replace pk_id with your PRIMARY KEY column, or any UNIQUE NOT NULL (combination of) column(s).
The trick is that the UPDATE typically processes rows according to the sort order of the subquery in the FROM clause. Updating in ascending order should never hit a duplicate key violation.
And the ORDER BY clause of the window function row_number() imposes that sort order on the resulting set. That's an undocumented implementation detail, so you might want to add an explicit ORDER BY to the subquery. But since the behavior of UPDATE is undocumented anyway, it still depends on an implementation detail.
You can wrap that into a plain SQL function.
Solution 2
Consider not doing what you are doing at all. Gaps in sequential numbers are typically expected and not a problem. Just live with it. See:
Serial numbers per group of rows for compound key

Declaring and assigning values to variables in PostgreSQL

First of all, I'm a total beginner in SQL. I have a table with 50+ columns, and now I'm doing calculations (on created temp table), but in some formulas, I got parameters, for example: A = 3
(A*(Column5 + Column7))/2
So, what is the best way to assign a value to a parameter?
This is what I was thinking about
DECLARE A DOUBLE PRECISION:=3;
But I don't know how implementing it.
The with option essentially creates a temp table that you can reference in a sql statement within the same transaction.
Your best bet is to create a function and then pass it the value of the parameter at run time. eg.
CREATE FUNCTION addColumns(
A integer,
firstColumn integer,
secondColumn integer
)
RETURNS integer
AS
RETURN (A*(firstColumn + secondColumn))/2
LANGUAGE SQL
IMMUTABLE;
Then use this in your query like:
select addColumns(3, column5, column7)
from [table];
As I could understand you want to store values using variables.
This is already answered here : How to declare a variable in a PostgreSQL query
There are many solutions there, but I particularly like using a WITH clause as pointed in one of the answers, when using plain SQL. For more fancy things, you should write proper stored procedures.

DB2 Stored Procedures- looping through values?

Okay, so I'm a novice at writing stored procedures. I'm trying to perform a function similar to a foreach() you would see in a programming language. Right now I have a temp table populated with the values I'd like to loop through. I would like to (for each value in this table) execute a SQL statement based upon that value. So, here's my pseudocode to illustrate what I'm really after here:
foreach(value in my temp table) {
SELECT * FROM TABLE WHERE column_x = value
}
No I know nothing of stored procedures so how can I get this done? Here's my script so far:
DROP TABLE SESSION.X;
CREATE GLOBAL TEMPORARY TABLE
SESSION.X (
TD_NAME CHAR(30)
);
INSERT INTO
SESSION.X
SELECT DISTINCT
TD_NAME
FROM
DBA.AFFIN_PROG_REPORT
WHERE
TD_NAME IS NOT NULL;
Any help is very much appreciated!
You need, by example, a cursor.
See the example: https://stackoverflow.com/a/4975012/3428749
See the documentation: https://msdn.microsoft.com/pt-br/library/ms180169(v=sql.120).aspx

Return two values from a scalar SQL Function

I have a Scalar SQL function thats returns a decimal value, and this function is used in many stored procedures across my database. Now in some procedures, I need to set a value based on some criteria inside the function. To make it clearer, depending on some variables used in calculating the result of the function, I want to set another variable inside the Stored procedure, and return it to the client.
I don't want to change how the result is returned or the return type of the function. I am thinking of doing it by inserting the new value i want into an sql table and then reading it from the procedure, But is there another or better way to do it?
Thanks
No, you cannot. Functions are severely limited in SQL Server and do not allow any side effects.
What you can do, however, is convert your scalar function into a table function. In it, you can return a table with as many columns as you need, so returning more than one value is not a problem.
You have a couple of options
1) Change it from a function to a stored procedure, and add an output parameter.
2) Change it from a scalar function to a table valued function returning a single row, with the additional value as an additional column.
If you need to preserve the existing function signature then just create a new table valued function that does the work (As per option 2 above), and modify your existing function to select from the new table valued function.
Here is some example code demonstrating this:
-- the original scalar function
CREATE FUNCTION dbo.t1(#param1 INT)
RETURNS INT AS
BEGIN
RETURN #param1 + 1
END
GO
-- a new table valued function, that returns 2 values in a single row
CREATE FUNCTION dbo.t2(#param1 INT)
RETURNS TABLE AS
RETURN (SELECT #param1 + 1 AS [r1], #param1 + 2 AS [r2])
GO
-- the modified original function, now selecting from the new table valued function
CREATE FUNCTION dbo.t3(#param1 INT)
RETURNS INT AS
BEGIN
RETURN (SELECT r1 FROM dbo.t2(#param1))
END
GO
-- example usage
SELECT dbo.t1(1)
SELECT * FROM dbo.t2(1)
SELECT dbo.t3(1)
Table value functions that return a single row are my favorite technique when a single answer from a scalar function just isn't adequate (or slows the query too much). A table can have from zero to many rows. Once I realized a 'table' value function can be limited to returning only one row it became obvious that multiple questions that would require separate scalar functions can be accomplished in a single table value function. It's like a scalar function on steroids. I like to read in all needed data just once into an internal table variable, then manipulate that data assigning it to additional variables as needed, finally assembling the answers for the output 'table' of one record. My database environment is read only, not transaction based. Incredibly useful for large (Mult-TB) historical database like medical information. Frequently used to concatenate fields into an end user friendly 'sentence' to deal with data that can have zero to many values, like patient diagnosis. Outer Apply the table value function on filtered data and it is extremely efficient.

Function format number and how to use it in sql statement

For oracle,
If I have a table A with data in number (such as price), how to write a function to format a number(10,2) to 9,9999.99 (<< obvious format).
And then how to use this function in SQL statement for displaying the data in table A.
Thank you.
----- UPDATE -----
From kindly suggestions below, yes, I should not treat numbers in this way.
But I highly want to accomplish the task above
Here I come with the function
CREATE OR REPLACE FUNCTION Fmt_num(N1 in NUMBER)
RETURN CHAR
IS
BEGIN
RETURN TO_CHAR(N1,'FM9,9999.99');
END;
/
And I can use this with the SQL statement as follow
SELECT Fmt_num(price) from A;
It works ! However, Can anyone fixes the function above to let it works with "a number (10,2)"? Just this condition only. Thank you for your anticipate in this noob question. :)
Look at TO_CHAR function.
select to_char(price, 'FM9,999,999.99')
from A;