i'm getting this error on my code and I have no idea what might be. I just got started with PL/pgSQL. Sorry if it is a stupid question.
ERROR: syntax error at or near "CURSOR"
LINE 9: CURSOR reg_notif IS SELECT * FROM sv_notificacao;
^
********** Error **********
My Code:
CREATE OR REPLACE FUNCTION checa_multa()
RETURNS INT AS
$$
DECLARE
CURSOR reg_notif IS SELECT * FROM sv_notificacao;
BEGIN
OPEN reg_notif;
LOOP
FETCH reg_notif INTO rn_linha
IF rn_linha.placa_veiculo IN (SELECT sv_veiculo.placa FROM sv_veiculo) --A placa informada na notificação deverá existir no cadastro de veículos;
AND rn_linha.nro_cnh IN (SELECT sv_condutor.nro_cnh FROM sv_condutor) --O número da CNH deverá ser existir no cadastro de condu
AND rn_linha.data_hora IS NOT NULL --A dtaa informada deve estar preenchida
AND rn_linha.data_hora <= CURRENT_DATE -- A nada informada não deverá ser futura
AND rn_linha.velocidade_inf> 0 --velocidade apurada superior a zero
AND rn_linha.velocidade_via > 0 --valocidade da via superior a zero
THEN
CREATE TABLE sv_infracao
(
cod_infracao SERIAL PRIMARY KEY,
cod_cpf BIGINT,
cnh_condutor VARCHAR(11),
placa_veiculo VARCHAR(7),
data_hora TIMESTAMP DEFAULT NULL,
velocidade_inf INT DEFAULT NULL,
velocidade_via INT DEFAULT NULL,
CONSTRAINT sv_infracao_sv_condutor FOREIGN KEY (cnh_condutor) REFERENCES sv_condutor (nro_cnh),
CONSTRAINT sv_infracao_sv_veiculo FOREIGN KEY (placa_veiculo) REFERENCES sv_veiculo (placa)
);
INSERT INTO sv_infracao (cod_cpf, cnh_condutor, placa_veiculo, data_hora, velocidade_inf, velocidade_via)
VALUES rn_linha.cod_cpf, rn_linha.cnh_condutor, rn_linha.placa_veiculo, rn_linha.data_hora, rn_linha.velocidade_inf, rn_linha.velocidade_via) ;
ELSE
CREATE TABLE sv_log_erro
(
cod_log SERIAL PRIMARY KEY,
notificacao INT,
descricao_problema TEXT,
CONSTRAINT sv_log_erro_sv_notificacao FOREIGN KEY (notificacao) REFERENCES sv_notificacao (cod_notif)
);
--Placa nao esta cadastrada no cadaastro de veiculos
IF placa NOT IN (SELECT sv_veiculo.placa FROM sv_veiculo) THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'A Placa: ' || rn_linha.placa_veiculo || ' não foi localizada');
END IF;
--Condutor não localizado
IF cnh NOT IN (SELECT sv_condutor.nro_cnh FROM sv_condutor) THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'A CNH: ' || rn_linha.nro_cnh || ' do Condutor informado não foi localizada');
END IF;
--Data não informada
IF data IS NULL THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'Data não preenchida');
END IF;
--Data do futuro
IF data > CURRENT_DATE THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'Data de notificação informada é do futuro '||data);
END IF;
--Velocidade nao informada
IF velocidadeInf <= 0 THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'Velocidade apurada do veiculo '|| rn_linha.placa_veiculo ||' não informada');
END IF;
--Velocidade nao informada
IF velocidadeVia <= 0 THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'Velocidade da via do veículo '|| placarn_linha.placa_veiculo ||' não informada');
END IF;
END IF;
END LOOP;
CLOSE reg_notif;
RETURN retorno;
END;
$$ LANGUAGE plpgsql;
SELECT checa_multa()
Try changing few things like:
DECLARE CURSOR reg_notif FOR SELECT Field1, Field2 FROM sv_notificacao;
Using FOR instead of IS
Don't use * in SELECT list because we are fetching CURSOR value in single field i.e. "rn_linha" in our case. As * can return more then 1 fields which do not match with FETCH values.
Let use now if issue persist after changes.
Related
This code below dispalys this error
SQL Error [42601]: ERREUR: erreur de syntaxe à la fin de l'entrée
Où : fonction PL/pgSQL users_tables(), ligne 26 à RETURN QUERY
I do not understand why !
In fact i launched the query inside the loop and it works fine
I do not see any logical error in my code
DROP FUNCTION users_tables();
create or replace
function users_tables()
returns table (table_name text, id int)
language plpgsql
as $function$
declare
_table_name text;
_column_name text;
begin
for _table_name,_column_name in
select
distinct t.table_name,
c2.column_name
from
information_schema.tables t
inner join information_schema.columns c1 on
c1.table_name = t.table_name
and c1.table_schema = t.table_schema
and c1.column_name = 'utilisateur_fk'
inner join information_schema.columns c2 on
c2.table_name = t.table_name
and c2.table_schema = t.table_schema
and lower(c2.column_name) like 'date%'
order by
t.table_name,
c2.column_name
limit
2
loop
return QUERY execute
'SELECT ' || _column_name || ',id FROM ' _table_name;
end loop;
end
$function$
;
select users_tables();
Could you please help me ?
you probably should write :
'SELECT ' || _column_name || ',id FROM ' || _table_name;
with || before _table_name.
the situation.
I'm producing a function, and part of it needs to get the name of each table by concatenating schemaname.tablename to iterate.
part of the code:
the part that it´s producing the error:
select schemaname||'.'||tablename as otra from pg_tables where schemaname = 'vigano' and pg_tables.tablename ~ 'ver1920_soja_filtrado$'
The hole function is this one:
CREATE OR REPLACE FUNCTION yield_summary()
RETURNS TABLE (
promedio double precision,
minimo double precision,
maximo double precision
) LANGUAGE plpgsql AS
$$DECLARE
v_sql text := '';
v_sep text := '';
v_tab text;
BEGIN
FOR v_tab IN
select schemaname||'.'||tablename as otra from pg_tables where schemaname = 'vigano' and pg_tables.tablename ~ 'ver1920_soja_filtrado$'
LOOP
v_sql := v_sql || v_sep ||
format(
'select round(avg(masa_de_re)::numeric,3) as promedio, round(min(masa_de_re)::numeric,3) as minimo, round(max(masa_de_re)::numeric,3) as maximo
FROM %I',
v_tab
);
v_sep := ' UNION ALL ';
END LOOP;
RETURN QUERY EXECUTE v_sql;
END;$$;
it produces the right table schemaname.tablename, but..it doesn't recognize it because of the double quotes.
ERROR: no existe la relación «vigano.elcerro_elmolino_ver1920_soja_filtrado»
LINE 2: FROM "vigano.elcerro_elmolino_ver1920_soja_filtrado" UNI...
^
how do I get rid of the double quotes??
if i use quote_indent()
select quote_ident(schemaname||'.'||tablename) as otra from pg_tables where schemaname = 'vigano' and pg_tables.tablename ~ 'ver1920_soja_filtrado$'
it produces this:
ERROR: no existe la relación «"vigano.elcerro_elmolino_ver1920_soja_filtrado"»
LINE 2: FROM """vigano.elcerro_elmolino_ver1920_soja_filtrado""" ^
If I use quote_literal()
select quote_literal(schemaname||'.'||tablename) as otra from pg_tables where schemaname = 'vigano' and pg_tables.tablename ~ 'ver1920_soja_filtrado$'
it produces:
ERROR: no existe la relación «'vigano.elcerro_elmolino_ver1920_soja_filtrado'»
LINE 2: FROM "'vigano.elcerro_elmolino_ver1920_soja_filtrado'" U...
^
thanks
In FORMAT(), %I specifies an identifier, and is always quoted by double quotes...
Try this instead:
CREATE OR REPLACE FUNCTION yield_summary()
RETURNS TABLE (
promedio double precision,
minimo double precision,
maximo double precision
) LANGUAGE plpgsql AS $$
DECLARE
v_sql text := '';
v_sep text := '';
v_tab record;
BEGIN
FOR v_tab IN
SELECT schemaname, tablename FROM pg_tables WHERE schemaname = 'vigano' AND pg_tables.tablename ~ 'ver1920_soja_filtrado$'
LOOP
v_sql := v_sql || v_sep || format(
'SELECT round(avg(masa_de_re)::numeric,3) AS promedio, round(min(masa_de_re)::numeric,3) AS minimo, round(max(masa_de_re)::numeric,3) AS maximo
FROM %I.%I',
v_tab.schemaname, v_tab.tablename
);
v_sep := ' UNION ALL ';
END LOOP;
RETURN QUERY EXECUTE v_sql;
END;
$$;
Don't pass schema name and table name as a single value to format(). Select two columns and pass two parameters.
FOR v_tab IN
select schemaname, tablename as otra from pg_tables where schemaname = 'vigano' and pg_tables.tablename ~ 'ver1920_soja_filtrado$'
LOOP
v_sql := v_sql || v_sep ||
format(
'select round(avg(masa_de_re)::numeric,3) as promedio, round(min(masa_de_re)::numeric,3) as minimo, round(max(masa_de_re)::numeric,3) as maximo
FROM %I.%I',
v_tab.schemaname, v_tab.tablename
);
v_sep := ' UNION ALL ';
END LOOP;
The way you used it, makes the format() function "think" that it's a single identifier that contains a . - which would require quoting.
Unrelated to your question, but you can simplify your code and get rid of the FOR loop completely:
select string_agg(
format('select round(avg(masa_de_re)::numeric,3) as promedio, round(min(masa_de_re)::numeric,3) as minimo, round(max(masa_de_re)::numeric,3) as maximo
FROM %I.%I',
schemaname, tablename), ' UNION ALL ')
into v_sql
from pg_tables
where schemaname = 'vigano'
and pg_tables.tablename ~ 'ver1920_soja_filtrado$';
return query
execute v_sql;
Data is not returned by the function even though all calculations are done and i can see the messages in the console with the information.
If tried creating a record variable to store the values and return next for each row.
CREATE OR REPLACE FUNCTION recompra ()
RETURNS TABLE (
anho INTEGER,
cod_cliente INTEGER,
cliente VARCHAR(255),
cantidad INTEGER,
clasificacion VARCHAR(64)
) AS $$
DECLARE
anho INTEGER;
cod_cliente INTEGER;
cliente VARCHAR(255);
cantidad INTEGER;
clasificacion VARCHAR(64);
anhos_anteriores INTEGER;
BEGIN
FOR anho IN (SELECT DISTINCT(EXTRACT(YEAR FROM v.fecha_factura)) as anhos
FROM ventas_vehiculos as v
GROUP BY anhos
ORDER BY anhos ASC) LOOP
BEGIN
FOR cod_cliente , cliente IN (SELECT d.cod_cliente, CONCAT(TRIM(d.nombre),' ',TRIM(d.apellido))
FROM clientes as d WHERE estado_cliente <> 'Inactivo' LIMIT 10) LOOP
-- TRAE LAS VENTAS POR ANHO
BEGIN
FOR cantidad IN SELECT COUNT(f.nro_factura) FROM ventas_vehiculos as f
WHERE f.cliente = cod_cliente
AND EXTRACT(YEAR FROM f.fecha_factura) =anho LOOP
SELECT COUNT(f.nro_factura) FROM ventas_vehiculos as f
WHERE f.cliente = cod_cliente
AND extract(YEAR FROM f.fecha_factura) < anho INTO anhos_anteriores;
IF (cantidad >0 AND anhos_anteriores > 1) THEN
clasificacion = 'Recompra';
ELSIF (cantidad > 0 AND anhos_anteriores = 0) then
clasificacion = 'Compra';
ELSIF (cantidad =0) THEN
clasificacion = 'No compra';
RAISE NOTICE '% -- % -- % -- % -- % --', anho,cod_cliente,cliente,cantidad,clasificacion;
END IF;
END LOOP; --- cierra loop cantidades por anho
END; -- cierra trae ventas por anho
END LOOP; --- cierra for clientes
END; -- cierra begin clientes
END LOOP; -- CIERRA FOR ANHOS
END;
$$ LANGUAGE plpgsql;
expected output
year cod_cliente nombre cantidad clasificacion
2018 1234 Juan 12 compra
2016 3232 pedro 1 recompra
There are many problems with your code, I'll list those I can see right away:
There is no RETURN NEXT statement in your code. You'll have to have one for every row you want to return.
You declare local variables with the same name as the output parameters, which will lead to a name conflict. Don't do that. The return parameters in the RETURNS TABLE clause already are PL/pgSQL variables.
You should use := rather than = for assignment. This is the supported way and avoids confusion with the comparison operator.
I'm changing column lengths for all necessary tables but I got some errors.
I am using PostgreSQL 10 and pgAdmin4 but I couldn't see error messages.
I guess, because of the pgAdmin version. Firstly, I couldn't declare CURSOR, I don't know why? I had succeeded on Oracle.
Can you help me about this situation? My code as shown below;
do $$
DECLARE
modify_column_cursor CURSOR FOR
SELECT 'ALTER TABLE "schema_name"."' || C.TABLE_NAME || '" ALTER COLUMN'|| C.COLUMN_NAME||' varchar(128)' as alter_sql, TABLE_NAME t_name, COLUMN_NAME c_name, 128 c_length FROM information_schema.columns c WHERE column_name LIKE '%PROD_NUM' and TABLE_NAME not like '%STAGING%' UNION
SELECT 'ALTER TABLE "schema_name"."' || C.TABLE_NAME || '" ALTER COLUMN'|| C.COLUMN_NAME||' varchar(128)' as alter_sql, TABLE_NAME t_name, COLUMN_NAME c_name, 128 c_length FROM information_schema.columns c WHERE column_name LIKE '%PREV_PROD_NUM' and TABLE_NAME not like '%STAGING%';
--.
--.
--.
sql_stmt VARCHAR(800);
c_length numeric;
c_length_db numeric;
flag numeric := 0;
BEGIN
--OPEN modify_column_cursor;
for modify_column in modify_column_cursor LOOP
raise notice 'asd : %', modify_column.ex_name;
sql_stmt := 'SELECT character_maximum_length FROM information_schema.columns WHERE column_name = ''' || modify_column.c_name || ''' and table_name = ''' || modify_column.t_name || ''' and table_schema = ''schema_name''';
EXECUTE sql_stmt INTO c_length_db;
IF c_length_db > modify_column.c_length THEN
sql_stmt := 'select max(length(' || modify_column.c_name || ')) from "schema_name".' || modify_column.t_name;
EXECUTE sql_stmt INTO c_length;
IF c_length > modify_column.c_length THEN
flag := 1;
raise notice '--------------INCONSISTENED FIELD FOUND---------------';
raise notice '% - % - % Not Ok! Default field size in db: %', modify_column.t_name, modify_column.c_name, modify_column.c_length, c_length_db;
raise notice '% - % - % Not Ok! Field has a data with length: %', modify_column.t_name, modify_column.c_name, modify_column.c_length, c_length;
raise notice '-------------------------------------------------------';
raise notice ' ';
ELSE
NULL;
END IF;
ELSE
NULL;
END IF;
END LOOP;
IF flag = 0 THEN
FOR modify_column IN modify_column_cursor
LOOP
EXECUTE modify_column.alter_sql;
END LOOP;
raise notice ' ';
raise notice '-----FIELDS ARE SUCCESSFULLY MODIFIED-----';
ELSE
raise notice ' ';
raise notice '-----ERROR: SOME FIELDS ARE NOT SUITABLE TO ALTER-----';
END IF;
end$$;
I am on PostgreSQL 11 but if I remember well its pretty much the same.
If you want to absolutely use a loop to do that I corrected a little your code and injected a debug table.
You had a missing blank space and a wrong declaration of the cursor. I simply got ride of it.
You can read this excellent article on cursor on postgresql if you want : http://www.postgresqltutorial.com/plpgsql-cursor/
do $$
DECLARE
sql_stmt VARCHAR(800);
c_length numeric;
c_length_db numeric;
flag numeric := 0;
modify_column record;
begin
create table if not exists [your_schema_name].test (query varchar);
for modify_column in
SELECT 'ALTER TABLE "'||[your_schema_name]||'"."' || C.TABLE_NAME || '" ALTER COLUMN '|| C.COLUMN_NAME||' varchar(128)' as alter_sql
, TABLE_NAME t_name
, COLUMN_NAME c_name
, 128 c_length
FROM information_schema.columns c
where table_schema = ''||[your_schema_name]||''
LOOP
--raise notice 'asd : %', modify_column.ex_name;
sql_stmt := 'SELECT character_maximum_length FROM information_schema.columns WHERE column_name = ''' || modify_column.c_name || ''' and table_name = ''' || modify_column.t_name || ''' and table_schema = '''||[your_schema_name]||'''';
insert into [your_schema_name].test values (sql_stmt);
EXECUTE sql_stmt INTO c_length_db;
IF c_length_db > modify_column.c_length THEN
sql_stmt := 'select max(length(' || modify_column.c_name || ')) from "'||[your_schema_name]||'".' || modify_column.t_name;
--EXECUTE sql_stmt INTO c_length;
insert into [your_schema_name].test values (sql_stmt);
IF c_length > modify_column.c_length THEN
flag := 1;
raise notice '--------------INCONSISTENED FIELD FOUND---------------';
raise notice '% - % - % Not Ok! Default field size in db: %', modify_column.t_name, modify_column.c_name, modify_column.c_length, c_length_db;
raise notice '% - % - % Not Ok! Field has a data with length: %', modify_column.t_name, modify_column.c_name, modify_column.c_length, c_length;
raise notice '-------------------------------------------------------';
raise notice ' ';
ELSE
NULL;
END IF;
ELSE
NULL;
END IF;
END LOOP;
IF flag = 0 THEN
--FOR modify_column IN modify_column_cursor
-- LOOP
-- EXECUTE modify_column.alter_sql;
--END LOOP;
raise notice ' ';
raise notice '-----FIELDS ARE SUCCESSFULLY MODIFIED-----';
ELSE
raise notice ' ';
raise notice '-----ERROR: SOME FIELDS ARE NOT SUITABLE TO ALTER-----';
END IF;
end;
$$;
I have a query which is assigned to some variable and I want to execute it with setting some values.
Example:
create or replace function funct1(a int)
returns void as
$$
declare
wrclause varchar := '';
sqlq varchar ;
t varchar;
begin
IF (a IS NOT NULL ) THEN
wrclause := 'where C = '|| a ||' AND C IN ('|| a || ')';
END IF;
sqlq := ' t :=select string_agg(''select *, abcd as "D" from '' || table_namess ||, '' Union all '') as namess
from tablescollection2 ud
inner join INFORMATION_SCHEMA.Tables so on ud.table_namess = so.Table_name ' || wrclause;
raise info '%',sqlq;
execute sqlq; /* How to set value to variable f.ex (t varchar output,t output)*/
raise info '%',t;
end;
$$
language plpgsql;
In SQL Server: We can use
exec sp_executesql #sqlq, N'#t nvarchar(max) output', #t OUTPUT;
Note: How can I do in the PostgreSQL?
MyTry:
execute sqlq(t varchar output,t output); /* getting error near varchar */
You can do something like
EXECUTE sqlq INTO target_variable;
for more help plpgsql-statements