Can't run "for loop" in PostgreSQL - sql

I'm trying to create temp table and insert some data from LOOP.
I need to count all strings on each table, but i have error like this:
ERROR: ОШИБКА: переменная цикла по кортежам должна быть переменной типа запись или списком скалярных переменных
LINE 16: for r in (select "table_name", "name_campaign" from "Table_7...
^
SQL state: 42601
Character: 206
Table names all in one existing table.
do
$body$
declare
v_count integer;
begin
set enable_seqscan = off;
drop table if exists tmp_statyks;
create temp table tmp_statyks(table_name varchar(60), name varchar(60), x_count int);
for r in (select "table_name", "name_campaign" from "Table_7517829240")
loop
execute immediate 'select count(*) from ' || r."table_name"
into v_count;
INSERT INTO tmp_statyks("table_name", "name" , "x_count")
VALUES (r."table_name",r."name_campaign",v_count);
end loop;
end
$body$
language 'plpgsql';
select * from tmp_statyks

Just declare r as record:
declare
v_count integer;
r record;
begin

Related

Include parameter in function to UNION multiple PostgreSQL tables

I have developed a function to UNION ALL tables from a list of table names (a table called tablelist below) inspired by this SO post.
The initial function just returns a selection, but now I'd like to write a new table with a name taken from a parameter new_table_name.
I'm struggling with the syntax to insert the parameter into the DROP TABLE AND CREATE TABLE statements. Here's one of the attempts which returns ERROR: mismatched parentheses at or near ";"
DROP FUNCTION IF EXISTS f_multi_union(text);
CREATE OR REPLACE FUNCTION f_multi_union(new_tab_name text)
RETURNS Table (my_id int, metric double precision, geom geometry)
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE
(
DROP TABLE IF EXISTS working.'' || new_tab_name || '';
CREATE TABLE working.'' || new_tab_name || '' AS (
SELECT string_agg(format('SELECT * FROM %s', tbl), ' UNION ALL ')
FROM (SELECT tbl FROM working.tablelist) sub
)
);
END
$func$;
Something like this?
DROP FUNCTION IF EXISTS f_multi_union(text);
CREATE OR REPLACE FUNCTION f_multi_union(new_tab_name text)
RETURNS void -- nothing to return
LANGUAGE plpgsql AS
$func$
DECLARE
_sql TEXT;
BEGIN
_sql := format('DROP TABLE IF EXISTS working.%I;', new_tab_name); -- avoid SQL injection
EXECUTE _sql;
_sql := 'SELECT string_agg(format(''SELECT * FROM %I'', tbl), '' UNION ALL '')
FROM (SELECT tbl FROM working.tablelist) sub;';
EXECUTE _sql
INTO _sql; -- overwrite current _sql content
_sql := format('CREATE TABLE working.%I AS %s;', new_tab_name, _sql);
EXECUTE _sql;
END
$func$;
I would replace the * in the SELECT statement with the columns that you need.

Fetch refcursor into temporary table

I need fetch refcursor into temporary table. Each refcursor column should match appropriate table column + one key (enumerate) column should be in temp table. For example refcursor return below data:
'one' 'Monday'
'two' 'Friday'
And the data which should store in table:
1 'one' 'Monday'
2 'two' 'Friday'
This refcursor is opened in other functions. So I does not know what columns should be in result set.
How I can implement something like FETCH ALL curs INTO temp_table ?
I wrote below function but it throws the error for (V_CURS_Rec).*
CREATE OR REPLACE FUNCTION FN_TEST()
RETURNS VOID LANGUAGE plpgsql
AS $$
DECLARE
V_CURS REFCURSOR;
V_CURS_Rec RECORD;
ITER INTEGER;
BEGIN
create temporary table if not exists TMP_TBL
(
INDX INTEGER NOT NULL,
CNAME VARCHAR(20),
CDAY VARCHAR(20),
);
DELETE FROM TMP_TBL;
SELECT * FROM FN_RET_REFCURSOR() INTO V_CURS;
ITER := 1;
LOOP
FETCH V_CURS INTO V_CURS_Rec;
EXIT WHEN NOT FOUND;
INSERT INTO TMP_TBL SELECT ITER, (V_CURS_Rec).*;
ITER := ITER + 1;
END LOOP;
RETURN;
END; $$;
As a workaround I have done below
CREATE OR REPLACE FUNCTION FN_TEST()
RETURNS VOID LANGUAGE plpgsql
AS $$
DECLARE
V_CURS REFCURSOR;
V_Rec_CNAME VARCHAR(20);
V_Rec_CDAY VARCHAR(20);
ITER INTEGER;
BEGIN
create temporary table if not exists TMP_TBL
(
INDX INTEGER NOT NULL,
CNAME VARCHAR(20),
CDAY VARCHAR(20)
);
DELETE FROM TMP_TBL;
SELECT * FROM FN_RET_REFCURSOR() INTO V_CURS;
ITER := 1;
LOOP
FETCH V_CURS INTO V_Rec_CNAME, V_Rec_CDAY;
EXIT WHEN NOT FOUND;
INSERT INTO TMP_TBL VALUES (ITER, V_Rec_CNAME, V_Rec_CDAY);
ITER := ITER + 1;
END LOOP;
RETURN;
END; $$;

Execute immediate statement

I'm trying to insert data into table using execute immediate statement. But I get an error
FROM keyword not found where expected
Could anyone take a look what's wrong?
declare
c1 SYS_REFCURSOR;
v_tabl_name varchar2(30);
begin
open c1 for
select tablename from table1;
LOOP
FETCH c1 INTO v_tabl_name;
EXIT WHEN c1%NOTFOUND;
execute immediate 'insert tabl2(tabl_name) (select ''tem'' from'||v_tabl_name||')' ;
END LOOP;
close c1;
end;
create table table1(tem varchar2(50), tablename varchar2(50));
create table tabl2(tabl_name varchar2(50));
insert into table1(tem, tablename) values ('table1','table1');
begin
for rc in (select tablename from table1) loop
--dbms_output.put_line('insert into tabl2(tabl_name) (select ''tem'' from '||rc.tablename||')');
execute immediate 'insert into tabl2(tabl_name) (select ''tem'' from '||rc.tablename||')' ;
end LOOP;
end;

PL/SQL if table not exist create

Hello i use oracle SQL developer
I have create a procedure, and i need to check if a table exist, if not exist i must create how can do?
I have try this
DECLARE v_emp int:=0;
BEGIN
SELECT count(*) into v_emp FROM dba_tables;
if v_emp = 0 then
EXECUTE IMMEDIATE 'create table EMPLOYEE ( ID NUMBER(3), NAME VARCHAR2(30) NOT NULL)';
end if;
END;
but give me an error 00103 because not find table
Just execute the create and watch the exception if thrown. Oracle would never replace the DDL of a table.
declare
error_code NUMBER;
begin
EXECUTE IMMEDIATE 'CREATE TABLE EMPLOYEE(AGE INT)';
exception
when others then
error_code := SQLCODE;
if(error_code = -955)
then
dbms_output.put_line('Table exists already!');
else
dbms_output.put_line('Unknown error : '||SQLERRM);
end if;
end;
You can run this for example:
if (select count(*) from all_tables where table_name = 'yourTable')>0 then
-- table exists
else
-- table doesn't exist
end if;
You should try following,
declare
nCount NUMBER;
v_sql LONG;
begin
SELECT count(*) into nCount FROM dba_tables where table_name = 'EMPLOYEE';
IF(nCount <= 0)
THEN
v_sql:='
create table EMPLOYEE
(
ID NUMBER(3),
NAME VARCHAR2(30) NOT NULL
)';
execute immediate v_sql;
END IF;
end;

In MySQL: How to pass a table name as stored procedure and/or function argument?

For instance, this does not work:
DELIMITER //
CREATE PROCEDURE countRows(tbl_name VARCHAR(40))
BEGIN
SELECT COUNT(*) as ct FROM tbl_name;
END //
DELIMITER ;
CALL countRows('my_table_name');
Produces:
ERROR 1146 (42S02): Table 'test.tbl_name' doesn't exist
However, this works as expected:
SELECT COUNT(*) as ct FROM my_table_name;
What syntax is required to use an argument as a table name in a select statement? Is this even possible?
Prepared statements are what you need.
CREATE PROCEDURE `test1`(IN tab_name VARCHAR(40) )
BEGIN
SET #t1 =CONCAT('SELECT * FROM ',tab_name );
PREPARE stmt3 FROM #t1;
EXECUTE stmt3;
DEALLOCATE PREPARE stmt3;
END $$
You can do it like this:
DROP PROCEDURE IF EXISTS `getDataUsingSiteCode`;
DELIMITER $$
CREATE PROCEDURE `getDataUsingSiteCode`(
IN tab_name VARCHAR(40),
IN site_ VARCHAR(255)
)
BEGIN
SET #site_code = site_;
SET #sql_ =CONCAT('SELECT * FROM ',tab_name,' WHERE site=?');
PREPARE statement_ FROM #sql_;
EXECUTE statement_ using #site_code;
END$$
DELIMITER ;