Oracle stored procedure with parameter - sql

I am fairly new to Oracle SQL. I am trying to create a stored procedure which takes 2 parameters. I am getting errors when I save below. Any idea ?
CREATE OR REPLACE PROCEDURE SWAP_VIEWS
(
SchemaName NVARCHAR,
TableName NVARCHAR
) AS
BEGIN
DECLARE SQLstring NVARCHAR :=
'ALTER VIEW AS POL.V_' + TableName + ' as SELECT * FROM ' + SchemaName + '.' + TableName
EXEC SQLstring;
END SWAP_VIEWS ;

Here the version corrected
CREATE OR REPLACE PROCEDURE SWAP_VIEWS
(
SchemaName NVARCHAR,
TableName NVARCHAR
) AS
SQLstring varchar2(4000);
BEGIN
SQLstring := 'CREATE OR REPLACE FORCE VIEW POL.V_' || TableName || ' as SELECT * FROM ' || SchemaName || '.' || TableName ' ;
EXECUTE IMMEDIATE SQLstring;
END SWAP_VIEWS ;
/
The concatenation character is |
The variable SQLString must be declared
The way to execute a variable is EXECUTE IMMEDIATE
You can use CREATE OR REPLACE FORCE VIEW instead of ALTER VIEW

You seem to be mixing SQL Server and Oracle syntax here:
Oracle uses standard operator || for string concatenation, not +
Oracle wants EXECUTE IMMEDIATE instead of EXEC
you need CREATE OR REPLACE VIEW
NVARCHAR2 should be preferred to NVARCHAR
Note that you don't need an intermediate variable assignment, you can concatenate the query string and execute it at once.
Consider:
CREATE OR REPLACE PROCEDURE SWAP_VIEWS (
pSchemaName NVARCHAR2,
pTableName NVARCHAR2
) AS
BEGIN
EXECUTE IMMEDIATE 'CREATE OR REPLACE VIEW AS POL.V_'
|| pTableName + ' as SELECT * FROM '
|| pSchemaName || '.' || pTableName;
END;
/

I have taken your procedure and modified like below, see if it works. Additionally i want to say, you can explicitly do exception handling in the procedure to capture any error during the execution and also creating view with '*' has some disadvantages. Please chek
CREATE OR REPLACE PROCEDURE SWAP_VIEWS
(
p_schema_name IN NVARCHAR2,
p_table_name IN NVARCHAR2
)
IS
lo_sql_string NVARCHAR2(4000);
lo_view_name NVARCHAR2(30);
lo_table_name NVARCHAR2(30);
BEGIN
-- I just prefer local variables for convenience to avoid more complex string in actual one and also for debugging purpose
lo_view_name := 'POL.V_'||p_table_name;
lo_table_name := p_schema_name||'.'||p_table_name;
lo_sql_string:= 'create or replace view '||lo_view_name||
' as '||
'select * from '||lo_table_name;
EXECUTE IMMEDIATE lo_sql_string;
END SWAP_VIEWS;
/

Related

REPLACE() in Postgres can't replace data

I'm new in postgres, I'm creating a procedure to rename table constraint names using the REPLACE(). If I test all the variables in this procedure the data is there and if I replace it manually it can. The problem is when this procedure is running the constraint name doesn't change.
create or replace procedure public.rename_existing_constraint_table(in table_name text, in date_now text, in list_constraint text[])
as $$ declare
const text;
table_rename text;
begin
table_rename := (select concat(table_name, '_', date_now));
if array_length(list_constraint, 1) >= 1 then
foreach const in array list_constraint loop
execute 'alter table if exists ' || table_name || ' RENAME CONSTRAINT ' || const || ' to ' || replace(const, table_name, table_rename);
end loop;
end if;
end $$
language plpgsql;
duplicate error because the data was not successfully renamed, it should be
app_devlogdetail_pkey to app_devlogdetail_20221214_pkey
psycopg2.errors.DuplicateTable: relation "app_devlogdetail_pkey" already exists
CONTEXT: SQL statement "alter table if exists app_devlogdetail_20221214 RENAME CONSTRAINT app_devlogdetail_pkey to app_devlogdetail_pkey"
PL/pgSQL function rename_existing_constraint_table(text,text,text[]) line 10 at EXECUTE
I have tried running the REPLACE() outside the procedure and it runs normally and the data can be changed, but when it is run inside the procedure to be executed the REPLACE() can't changed data. How to make the REPLACE() can run and the data can be changed or is there some other way around it?

How to assign the returned value from a Snowflake SQL stored procedure into variable?

I am creating a stored procedure in Snowflake that returns number of rows in a table. Here is the code for the procedure and the result.
CREATE OR REPLACE PROCEDURE CDS_EXTRACT_CHECK_ROWCOUNT(STAGE_DATABASE varchar, STAGE_SCHEMA varchar, STAGE_TABLE varchar)
RETURNS table (a int)
LANGUAGE SQL
AS
DECLARE
stmt string;
res resultset;
rowcount int;
BEGIN
stmt := 'SELECT COUNT(*) FROM ' || :STAGE_DATABASE || '.' || :STAGE_SCHEMA || '.' || :STAGE_TABLE || ';';
res := (EXECUTE IMMEDIATE :stmt);
RETURN TABLE(res);
END
;
I want to execute this stored procedure within another procedure and store the returned value to a variable:
rowcount := CALL CDS_EXTRACT_CHECK_ROWCOUNT(:STAGE_DATABASE, :STAGE_SCHEMA, :STAGE_TABLE);
Thanks in advance
You can use RESULT_SCAN to read the value returning from your stored procedure:
https://docs.snowflake.com/en/sql-reference/functions/result_scan.html
For example:
...
CALL CDS_EXTRACT_CHECK_ROWCOUNT(:STAGE_DATABASE, :STAGE_SCHEMA, :STAGE_TABLE);
select $1 into :rowcount from table(result_scan(last_query_id()));
...
You can use the below version:
CREATE OR REPLACE PROCEDURE CDS_EXTRACT_CHECK_ROWCOUNT(
STAGE_DATABASE varchar,
STAGE_SCHEMA varchar,
STAGE_TABLE varchar
)
RETURNS INT
LANGUAGE SQL
AS
DECLARE
table_path string;
rowcount int;
BEGIN
table_path := :STAGE_DATABASE || '.' || :STAGE_SCHEMA || '.' || :STAGE_TABLE;
SELECT COUNT(*) INTO :rowcount FROM identifier(:table_path);
return :rowcount;
END
;

Select into record dynamically

I have a type table_array which is a table of t_timestamp records. This record is as below:
TYPE t_timestamp IS RECORD (
table_name VARCHAR2(50),
table_id VARCHAR2(50),
table_timestamp TIMESTAMP(6)
);
I later declare an instance of this table_array as below:
l_tables table_array := table_array();
I would like to create a procedure add_to_record() to easily add to this table_array by doing something like the following:
l_tables.extend;
add_to_record(l_tables, 'table_name', 'CRE_SHRE_CLASS');
add_to_record(l_tables, 'table_id', share_class_id);
add_to_record(l_tables, 'table_timestamp', l_table_timestamp);
Inside add_to_record(), I initially tried using EXECUTE IMMEDIATE to dynamically insert into to the record based on the passed parameters like below:
PROCEDURE add_to_record (tables IN OUT table_array, key IN VARCHAR2, value IN VARCHAR2)
IS
BEGIN
EXECUTE IMMEDIATE '
SELECT
' || value || '
INTO tables(tables.last).' || key || '
FROM dual'
;
END add_to_record;
However, this didn't work as the correct syntax for inserting into a variable using EXECUTE IMMEDIATE is EXECUTE_IMMEDIATE some_query INTO some_variable. This leaves me in a predicament though. Because I can do the following:
l_select_value_from_dual_query := '
SELECT
' || value || '
FROM dual'
;
But the variable that I want to insert this value into is itself dynamic, and from what I can see, the INTO some_variable part of an EXECUTE IMMEDIATE query cannot be dynamic. So the following doesn't work:
EXECUTE IMMEDIATE l_select_value_from_dual_query INTO tables(tables.last).' || key || ';
Is there any way around this? I'd like to avoid some sort of IF-THEN-ELSE if possible.

snowflake procedure syntax error while querying information schema

Idea is I am trying to query information schema metadata and build columns based on datatypes if date then I create min date max date ,if number then check count of distinct or count rows
I have simplified now I will pass dbname , schema name and table name as parameters,
My output should return with below columns
SCHEMA_NM,TBL_NAME,_COUNT,_DISTINCT_COUNT,_MIN_DATE,_MAX_DATE.
For testing purpose at least if two measure is syntactically correct remaining I will take care
CREATE OR REPLACE PROCEDURE PROFILING( DB_NAME VARCHAR(16777216),TBL_SCHEMA VARCHAR(16777216), TBL_NAME VARCHAR(16777216))
RETURNS VARCHAR(16777216)
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
BEGIN
create or replace temporary table tbl_name as (select case when data_type=NUMBER then (execute immediate 'select count(col_val) from ' || :1 || '.' || :2 || '.' || :3) else null end as col_value_num,case when data_type=DATE then (execute immediate 'select count(col_val) from ' || :1 || '.' || :2 || '.' || :3) else null end as col_min_date from ':1.information_schema.columns where table_catalog=:1 and table_schema=:2 and table_name=:3 ' )) ;
insert into some_base_table as select * from tbl_name;
truncate tbl_name
RETURN 'SUCCESS';
END;
$$;
With above query I am getting below error
error : SQL compilation error: Invalid expression value (?SqlExecuteImmediateDynamic?) for assignment.
Any help here please
There are multiple errors in your code, but the error you mentioned is about this line:
num := (execute immediate "select count(col_val) from tab_cat.tab_schema.tab_name") ;
NUM is declared as integer, you can't directly assign a value from execute immediate. Execute immediate statement returns a resultset. To access the value you need to define a cursor and fetch the data.
The SQL should be surrounded by single quotes (not double quotes), and you should also build the string correctly. Something like this:
result := (execute immediate 'select count(col_val) from ' || tab_cat || '.' || tab_schema || '.' || tab_name ) ;

He does not perform the procedure. Fail in first step. Oracle

I created procedure in oracle that drops my table and creates same table from my view. But I have some problems with running this procedure. First step with drop table works but copying it doesn't work.
It this a good procedure ?
create or replace PROCEDURE transfer_table (table_name IN VARCHAR2,tableFrom IN VARCHAR2) IS
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE ' || table_name;
EXECUTE IMMEDIATE 'CREATE TABLE ' || table_name || ' AS SELECT * FROM ' || tableFrom;
commit;
END transfer_table;
Next I click on this procedure and change the variable then view and click ok, but only the first step of dropping the table is working. What am I doing wrong ?
I think you need to catch the error if the table you are creating doesn't exist.
create or replace PROCEDURE transfer_table (table_name IN VARCHAR2,tableFrom IN VARCHAR2) IS
BEGIN
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE ' || table_name;
EXCEPTION WHEN OTHERS THEN
NULL;
END;
EXECUTE IMMEDIATE 'CREATE TABLE ' || table_name || ' AS SELECT * FROM ' || tableFrom;
commit;
END transfer_table;