HOW to resolve this problem ? :
CREATE OR REPLACE FUNCTION "BADIL_PROD"."FCT_UPDATE_POINTAGE" (id_projet in NUMBER)
return NUMBER
is
Results NUMBER;
CURSOR cur_update IS
SELECT distinct t.ID_TACHE,t.id_collaborateur,t.id_ref_rubrique_activite
FROM TACHES t
where t.ID_PROJET =id_projet ;
begin
dbms_output.enable(200000);
FOR cur in cur_update
LOOP
BEGIN
dbms_output.put_line(cur.ID_TACHE || '--' || cur.ID_COLLABORATEUR || '--' || cur.ID_REF_RUBRIQUE_ACTIVITE);
UPDATE POINTAGES p SET p.ID_TACHE_INCIDENT = cur.ID_TACHE
where p.id_projet_tma=id_projet
and p.ID_COLLABORATEUR = cur.ID_COLLABORATEUR
AND p.ID_REF_RUBRIQUE_ACTIVITE = cur.ID_REF_RUBRIQUE_ACTIVITE;
END;
END LOOP;
results:=0;
return(results);
end fct_update_pointage;
So when I want to test this function I get this error in data studio :
(specific name "FCT_UPDATE_POINTAGE") attempted to modify data but was
not defined as MODIFIES SQL DATA.. SQLCODE=-577,
This worked for me with DB2 V11 on Linux:
db2set DB2_COMPATIBILITY_VECTOR=830
db2stop
db2start
db2 create database mydb
db2 connect to mydb
db2 "create table taches(....)"
db2 "create table pointages(...)"
db2 -tvf FCT_UPDATE_POINTAGE.sql
(where FCT_UPDATE_POINTAGE.sql contains your function definition )
However, note the documented restriction in the documentation "Compiled SQL functions (including PL/SQL functions) that MODIFY SQL DATA can only be used as the only element on the right side of an assignment statement that is within a compound SQL (compiled) statement."
DB2 Version 9.7 allowed the "modifies sql data" clause when defining PL/SQL user defined functions, but IBM removed that ability at DB2 Version 10.1 and higher. Maybe you need to convert to an sproc.
Related
I am doing a procedure migration in pl / sql (oracle) to sql / pl (DB2) and I don't know how to pass a subprocedure to DB2
As I am not a system administrator I cannot change DB2 to be pl / sql compatible
EXAMPLE
create or replace PROCEDURE "SP_NOSTRADAMUS_PRODUTO"
AS
V_EXISTE_TAB NUMBER := 0;
PROCEDURE PR_HIRQ_PRODUTO_OR
AS
BEGIN
END
If your Db2-server runs on Linux/Unix/Windows, in ANSI SQL PL, if you have a local procedure nested within the body of another SQL PL procedure (or compound statement), then you use the DECLARE keyword to define the local procedure. This is supported by Db2-LUW in versions v10.1 and higher.
If you have very many Oracle PL SQL stored procedures, please discuss with your solution architect (if you have one) and your DBA about the possibility of configuring your Db2 server to support Oracle compatibility . This may save you some money.
You can see the Db2 syntax for SQL PL here (be sure to select the correct version of your Db2-server product in the pull down list).
There are some restrictions on local procedures, so study the documentation carefully. But your local procedure can access variables and objects defined in surrounding block(s) that are in scope.
Your example might look like this in ANSI SQL PL:
create or replace PROCEDURE "SP_NOSTRADAMUS_PRODUTO"
begin
declare V_EXISTE_TAB integer default 0;
declare PROCEDURE PR_HIRQ_PRODUTO_OR
BEGIN
-- body of pr_hirq_produto_or procedure
END;
-- body of sp_nostradamus_produto procedure
END
#
Db2 does not have subprocedures, not even sure why oracle would. In db2 you just create the 'sub' procedures as regular procedures and then 'CALL' them.
create procedure a( ....
create procedure b ....
create procedure main(...)
begin
call a(...);
call b(...);
end
I am attempting to get a better understanding of the DO command in postgreSQL 9.1
I have following code block,
DO
$do$
BEGIN
IF 1=1 THEN
SELECT 'foo';
ELSE
SELECT 'bar';
END IF;
END
$do$
However it returns the following error:
[42601] ERROR: query has no destination for result data Hint: If you want to discard the results of a SELECT, use PERFORM instead. Where: PL/pgSQL function "inline_code_block" line 4 at SQL statement
PostgreSQL DO command creates and executes some specific short life function. This function has not any interface, and then it cannot to return any output other then changes data in tables and some debug output.
Your example has more than one issues:
Only PostgreSQL table functions can returns some tabular data. But the mechanism is significantly different than MSSQL. PostgreSQL user's should to use RETURN NEXT or RETURN QUERY commands.
CREATE OR REPLACE FUNCTION foo(a int)
RETURNS TABLE(b int, c int) AS $$
BEGIN
RETURN QUERY SELECT i, i + 1 FROM generate_series(1,a) g(i);
END;
$$ LANGUAGE plpgsql;
SELECT * FROM foo(10);
DO anonymous functions are not table functions - so no output is allowed.
PostgreSQL 9.1 is not supported version, please upgrade
If you have some experience only from MSSQL, then forget it. A concept of stored procedures of PostgreSQL is very similar to Oracle or DB2, and it is significantly different to MSSQL does. T-SQL integrates procedural and SQL constructs to one set. Oracle, PostgreSQL, ... procedural functionality can embedded SQL, but procedural functionality is not integrated to SQL.
Please, read PostgreSQL PLpgSQL documentation for better imagine about this technology.
I am wondering if it's possible to use the result of a subquery as database name in a PostgreSQL (9.5.1) DDL statement.
For example, I wanted to alter the current database with something like:
ALTER DATABASE (SELECT current_database()) SET a_var TO 'a_value';
If I run this, an error occurs:
ERROR: syntax error at or near "("
LINE 1: ALTER DATABASE (SELECT current_database()) SET ...
What's the correct way to use the sub-query (if possible)?
You need dynamic SQL for that:
DO
$do$
BEGIN
EXECUTE format($f$ALTER DATABASE %I SET x.a_var TO 'a_value'$f$, current_database());
END
$do$;
Using format() to escape the db name safely while being at it.
BTW, to unset:
ALTER DATABASE your_db RESET x.a_var;
To see the current setting:
SELECT current_setting('x.a_var');
(The DB default is not active before you start a new session.)
Related:
Table name as a PostgreSQL function parameter
Error when setting n_distinct using a plpgsql variable
I am trying to create a table inside a function using dynamic SQL and immediately copy it into another table.
execute 'create table week_temp as
select w.*, ww.*
from employer_weekly w
left join employer_weekly_' || $1 || '_2 ww
on w.w_employer::int = ww.emp_' || $1 || '::int';
drop table if exists employer_weekly;
create table employer_weekly as select * from week_temp;
I am receiving the following error:
Error : ERROR: relation with OID 9288742 does not exist
CONTEXT: SQL statement "create table employer_weekly as select * from
week_temp"
Checking manually, I can see week_temp and can access it correctly.
Would appreciate any clues!
What #a_horse_with_no_name said.
But - the problem you are seeing is that the non-dynamic statements in your function are being compiled. This means the "FROM week_temp" is looking at an older version of week_temp that no longer exists. Make that statement dynamic SQL too and it should work.
I'm currently writing some installer script that fires SQL files against different database types depending on the system's configuration (the webapplication supports multiple database server like MySQL, MSSQL and PostgreSQL).
One of those types is PostgreSQL. I'm not fluent with it and I would like to know if it's possible to make a statement into a define/populate SQL file that makes an SQL query conditional to a specific PostgreSQL server version.
How to make an SQL statement conditionally in plain PGSQL so that it is only executed in version 9? The command is:
ALTER DATABASE dbname SET bytea_output='escape';
The version check is to compare the version with 9.
Postgres does have version() function, however there is no major_vesion(). Assuming that output string always includes version number as number(s).number(s).number(s) you could write your own wrapper as:
CREATE OR REPLACE FUNCTION major_version() RETURNS smallint
AS $BODY$
SELECT substring(version() from $$(\d+)\.\d+\.\d+$$)::smallint;
$BODY$ LANGUAGE SQL;
Example:
=> Select major_version();
major_version
---------------
9
(1 row)
However real issue here is that AFAIK you can't execute your commands conditionally in "pure" SQL and best what you can do is to write some stored function like this:
CREATE OR REPLACE FUNCTION conditionalInvoke() RETURNS void
AS $BODY$
BEGIN
IF major_version() = 9 THEN
ALTER DATABASE postgres SET bytea_output='escape';
END IF;
RETURN;
END;
$BODY$ LANGUAGE plpgsql;
I think that you should rather use some scripting language and generate appropriate SQL with it.
Or you could just use
select setting from pg_settings where name = 'server_version'
Or
select setting from pg_settings where name = 'server_version_num'
If you need major version only
select Substr(setting, 1, 1) from pg_settings where name = 'server_version_num'
or
select Substr(setting, 1, strpos(setting, '.')-1) from pg_settings where name = 'server_version'
if you want it to be compatible with two digit versions.
Maybe you could make things dependent on the output of
select version();
(probably you'll have to trim and substring that a bit)
BTW (some) DDL statements may not be issued from within functions; maybe you'll have to escape to shell-programming and here-documents.