Nested loop over selected row_to_json result - sql

I am trying to do a nested loop on the result of row_to_json() but getting below error.
DO
$BODY$
DECLARE
js jsonb := '{"ddd525b9-e47c-46ac-ab55-e0db93338ff3": "ddd525b9-e47c-46ac-ab55-e0db93338ff4", "550e8400-e29b-41d4-a716-446655440000": "e15c6fe3-000c-4c69-9c41-9e241323cbe5", "0ba26163-bf75-40d2-8526-172229604d95": "7ed83dbc-3895-490c-8a16-9842cfe85e28"}';
i record;
BEGIN
FOR i IN SELECT * FROM jsonb_each_text(js)
loop
DECLARE
orgs jsonb := (SELECT row_to_json(t) FROM (Select parent_id from my_schema.my_table o where o.id != i.value) t);
j record;
for j in select * from jsonb_each_text(orgs)
loop
RAISE NOTICE 'key %', j.key;
RAISE NOTICE 'value %', j.value;
end loop;
END LOOP;
END;
$BODY$;
Error:
SQL Error [42601]: ERROR: syntax error at or near "for"
Position: 506

You forgot the BEGIN and END around your second loop.
DO
$do$
DECLARE
js jsonb := '{"ddd525b9-e47c-46ac-ab55-e0db93338ff3": "ddd525b9-e47c-46ac-ab55-e0db93338ff4", "550e8400-e29b-41d4-a716-446655440000": "e15c6fe3-000c-4c69-9c41-9e241323cbe5", "0ba26163-bf75-40d2-8526-172229604d95": "7ed83dbc-3895-490c-8a16-9842cfe85e28"}';
i record;
BEGIN
FOR i IN (SELECT * FROM jsonb_each_text(js)) LOOP
DECLARE
orgs jsonb := (SELECT row_to_json(t) FROM (Select parent_id from my_schema.my_table o where o.id != i.value) t);
j record;
BEGIN
FOR j IN (select * from jsonb_each_text(orgs)) LOOP
RAISE NOTICE 'key %', j.key;
RAISE NOTICE 'value %', j.value;
END LOOP;
END;
END LOOP;
END;
$do$;

Related

"malformed array literal" error in PL/pgSQL

I got an error in PL/pgSQL:
"ERROR: malformed array literal: "2019-11-22 09:18:07.248537" DETAIL:
Array value must start with "{" or dimension information. CONTEXT:
PL/pgSQL function chargelengtth() line 11 at FOR over SELECT rows"
CREATE OR REPLACE FUNCTION chargelengtth() RETURNS text AS
$$
DECLARE chargetime integer;
DECLARE othertime integer;
DECLARE total integer;
DECLARE charge_length text[];
DECLARE chargestatus text;
DECLARE otherstatus text;
BEGIN
total := 0;
chargetime := 0;
FOR charge_length IN
SELECT * FROM table_name
LOOP
RAISE NOTICE 'Stuff: %', charge_length;
IF(charge_length[diagnostic] = 'Charging' AND chargetime = 0) THEN
chargetime := extract(epoch from charge_length[time]);
END IF;
IF(charge_length[diagnostic] != 'Charging') THEN
othertime := extract(epoch from charge_length[time]);
total := total + (othertime - chargetime);
chargetime := 0;
END IF;
END LOOP;
RETURN to_char(total * interval '1 sec','HH24h MIm');
END$$ LANGUAGE plpgsql;
SELECT * FROM chargelengtth()`
can you please share your knowledge to resolve this issue.
As documented in the manual you need to use a record variable when you want to loop over a SELECT statement:
CREATE OR REPLACE FUNCTION chargelengtth()
RETURNS text AS
$$
DECLARE
chargetime integer;
othertime integer;
total integer;
chargestatus text;
otherstatus text;
l_row record; --<< here
BEGIN
total := 0;
chargetime := 0;
FOR l_row IN SELECT * FROM table_name
LOOP
RAISE NOTICE 'Stuff: %', l_row;
IF (l_row.diagnostic = 'Charging' AND chargetime = 0) THEN
chargetime := extract(epoch from l_row.time);
END IF;
IF (l_row.diagnostic != 'Charging') THEN
othertime := extract(epoch from l_row.time);
total := total + (othertime - chargetime);
chargetime := 0;
END IF;
END LOOP;
RETURN to_char(total * interval '1 sec','HH24h MIm');
END$$ LANGUAGE plpgsql;
SELECT chargelengtth()
As far as I can tell, you can replace this with a single SELECT statement. Assuming the time column is a timestamp, I think the following is equivalent to what you are doing (except for the formatting of the interval at the end):
with ct (chargetime) as (
select time
from table_name
where diagnostic = 'Charging'
limit 1
)
select sum(t.time - ct.chargetime)
from the_table t
cross join ct
where t.diagnostic <> 'Charging'
The retrieval of the chargetime is a bit confusing as you seem to rely on some order of the rows, yet your query has no order by. The limit 1 without an order by does essentially the same, but if you want reproducible results you should really specify an order by (also for your FOR loop statement)

code goes into infinite loop when updating table's column

expert.
I'm new to PLSQL programming.
More than 200 tables have 'EXAMPLE' columns.
I want to update the column 'EXAMPLE' with 'YES'.
The purpose of the following code is to update the 'EXAMPLE' column for every 10000 records.
But I think the following code enters an infinite loop.
Where am I making a mistake?.
how can i fix this?
declare
v_match_count integer;
table_name varchar2(30);
begin
v_match_count:=0;
for tablolar in
(
SELECT table_name
FROM user_tab_columns,user_objects
WHERE
user_tab_columns.table_name=user_objects.object_name and user_objects.object_type not in ('VIEW') AND
column_name IN ( 'FILE_NO', 'PROT_NO' )
GROUP BY table_name
HAVING Count(*) > 1
) loop
begin
-- v_match_count:=v_match_count+1;
-- dbms_output.put_line(tablolar.table_name||' = '||v_match_count);
WHILE TRUE LOOP
IF tablolar.table_name||'.EXAMPLE' IS NOT NULL THEN --the line I changed in the code.
--dbms_output.put_line(tablolar.table_name||' = '||v_match_count||' girdi.');
execute immediate 'UPDATE HASTANE.'||tablolar.table_name|| ' SET EXAMPLE=''YES'' WHERE '||tablolar.table_name||'.EXAMPLE IS NULL AND ROWNUM<10000' ;
COMMIT;
END IF;
IF tablolar.table_name||'.EXAMPLE' IS NULL THEN --the line I changed in the code.
EXIT;
end if;
-- v_match_count:=v_match_count+1;
END LOOP;
v_match_count:=v_match_count+1;
dbms_output.put_line(tablolar.table_name||' = '||v_match_count);
end;
end loop;
end;
In the test for 'EXAMPLE' the value will never be NULL so you will never exit the loop. Try checking for the existence of the column 'EXAMPLE' in your query, then you can just do the update for each table and the loop will exit when all the records are read.
declare
v_match_count integer;
v_record_count INTEGER;
table_name varchar2(30);
begin
v_match_count:=0;
v_record_count := 0;
for tablolar in
(
SELECT table_name
FROM user_tab_columns,user_objects
WHERE
user_tab_columns.table_name=user_objects.object_name and user_objects.object_type not in ('VIEW') AND
column_name IN ( 'FILE_NO', 'PROT_NO' )
AND EXISTS (SELECT * FROM user_tab_columns x
WHERE x.table_name = user_tab_columns.table_name AND x.column_name = 'EXAMPLE')
GROUP BY table_name
HAVING Count(*) > 1
) loop
BEGIN
--- Get the record cound
execute immediate 'SELECT COUNT(*) FROM ' || 'HASTANE.' ||tablolar.table_name || ' WHERE '||tablolar.table_name||'.EXAMPLE IS NULL'
INTO v_record_count;
--- Do we have anything to update?
IF NVL(v_record_count,0) > 0 THEN
--- Update all the records that are NULL
FOR v_match_count IN 1..v_record_count LOOP
execute immediate 'UPDATE HASTANE.'||tablolar.table_name|| ' SET EXAMPLE=''YES'' WHERE '||tablolar.table_name||'.EXAMPLE IS NULL' ;
--- Check if it's time to COMMIT (every 10000 records)
IF MOD(v_match_count, 10000) = 0 THEN
COMMIT;
END IF;
END LOOP;
--- COMMIT remaining records since last COMMIT
COMMIT;
END IF;
end;
end loop;
end;

Create a NZPLSQL to find min(date) and a max(date) for a group of fields that serve as a key

I would like to know how I can execute a select from a procedure stored in Netezza.
I currently have the procedure under construction and I read that the raise notice serves to print on screen, however I do not know how (or if you can print a table in sql) just as if you were doing a query in traditional sql.
What the query is trying to do is that for a record,
COUNT (*) AS N_REPETITIONS,
CDS.CASO_PACIENTE_FK,
CDS.RESIVALITY_SPECIALITY_COD,
CDS.CASO_NIVEL_ATENCION_TIPO,
CDS.CASO_TIPO_PRESTACION_FK,
CDS.DIVING_DATE_DAY,
CDS.SALID_DATE_DAY
and that it gives me MIN(CDS.DERIVACION_FECHA_HORA) and MAX(CDS.SALIDA_FECHA_HORA) based on a key that are the fields.
If I have dates between MIN(CDS.DERIVACION_FECHA_HORA) and MAX(CDS.SALIDA_FECHA_HORA) for a CDS.CASO_PACIENTE_FK, i want that register added to number of register for each CDS.CASO_PACIENTE_FK
Here the code:
CREATE OR REPLACE PROCEDURE SP_ANALISIS_DUPLICADOS()
RETURNS REFTABLE(NETEZZA_PROD_LISTA_ESPERA_NOGES.LLAVE_CASOS_DUPLICADOS)
EXECUTE AS OWNER
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
num_args INTEGER;
I am just starting to work with Netezza.
Thank you in advance to whom you answer.
This is the code:
CREATE OR REPLACE PROCEDURE SP_ANALISIS_DUPLICADOS()
RETURNS REFTABLE(NETEZZA_PROD_LISTA_ESPERA_NOGES.LLAVE_CASOS_DUPLICADOS)
EXECUTE AS OWNER
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
num_args INTEGER;
typ oid;
idx INTEGER;
N_REPETICIONES NUMERIC(19);
CASO_PACIENTE_FK NUMERIC(19);
DERIVACION_ESPECIALIDAD_COD VARCHAR(255);
CASO_NIVEL_ATENCION_TIPO NUMERIC(19);
CASO_TIPO_PRESTACION_FK NUMERIC(19);
DERIVACION_FECHA_HORA TIMESTAMP;
SALIDA_FECHA_HORA TIMESTAMP;
--CURSOR FECHA_HORA_DERIVACION_MIN;
--CURSOR FECHA_HORA_SALIDA_MAX;
CURSOR CASO_PACIENTE_FK;
CURSOR DERIVACION_ESPECIALIDAD_COD;
CURSOR CASO_NIVEL_ATENCION_TIPO;
CURSOR CASO_TIPO_PRESTACION_FK;
--L_CONDITIONS VARCHAR(1000);
--Duplicados CNE MIN
BEGIN
num_args := PROC_ARGUMENT_TYPES.count;
FOR CASO_PACIENTE_FK IN
num_args := CASO_PACIENTE_FK.count;
--RAISE NOTICE ’Number of arguments: %’, num_args;
for i IN 0
CASO_PACIENTE_FK.count - 1 LOOP
typ := CASO_PACIENTE_FK(i);
idx := i+1;
FOR DERIVACION_ESPECIALIDAD_COD IN
num_args := DERIVACION_ESPECIALIDAD_COD.count;
for j IN 0
DERIVACION_ESPECIALIDAD_COD.count - 1 LOOP
typ := DERIVACION_ESPECIALIDAD_COD(j);
idx := j+1;
FOR CASO_NIVEL_ATENCION_TIPO IN
num_args := CASO_PACIENTE_FK.count;
--RAISE NOTICE ’Number of arguments: %’, num_args;
for k IN 0
CASO_NIVEL_ATENCION_TIPO.count - 1 LOOP
typ := CASO_NIVEL_ATENCION_TIPO(k);
idx := k+1;
FOR CASO_TIPO_PRESTACION_FK IN
num_args := CASO_TIPO_PRESTACION_FK.count;
--RAISE NOTICE ’Number of arguments: %’, num_args;
for a IN 0
CASO_TIPO_PRESTACION_FK.count - 1 LOOP
typ := CASO_TIPO_PRESTACION_FK(a);
idx := a+1;
--RAISE NOTICE ’argument $% is type % and has the value ’’%’’’,
--idx, typ, $idx;
F FLAG = 1 THEN
IF Fecha_Entrada = SELECT COUNT(*) AS N_REPETICIONES, MIN(CDS.DERIVACION_FECHA_HORA) AS FECHA_HORA_DERIVACION_MIN
FROM NETEZZA_PROD_SIGTE_DIARIO.SIG_CASO_DERIVACION_SALIDA CDS
WHERE (CDS.CASO_TIPO_PRESTACION_FK=1
OR CDS.CASO_TIPO_PRESTACION_FK=2)
--AND CDS.DERIVACION_FECHA_HORA >= CDS.DERIVACION_FECHA_HORA
GROUP BY CDS.CASO_PACIENTE_FK, CDS.DERIVACION_ESPECIALIDAD_COD, /*CDS.DERIVACION_ESTABLECIMIENTO_COD*/
CDS.CASO_NIVEL_ATENCION_TIPO, /*CDS.DERIVACION_FECHA_HORA,*/ CDS.CASO_TIPO_PRESTACION_FK, CDS.DERIVACION_FECHA_HORA,
CDS.SALIDA_FECHA_HORA
HAVING COUNT(*)>1
ORDER BY N_REPETICIONES, CDS.CASO_PACIENTE_FK, CDS.DERIVACION_FECHA_HORA, CDS.SALIDA_FECHA_HORA DESC
THEN Fecha_Entrada = 'TRUE';
ELSE FLAG = 0 THEN
Fecha_Entrada = 'FALSE'
F FLAG = 1 THEN
IF Fecha_Salida = SELECT COUNT(*) AS N_REPETICIONES, MAX(CDS.SALIDA_FECHA_HORA) AS FECHA_HORA_DERIVACION_MIN
FROM NETEZZA_PROD_SIGTE_DIARIO.SIG_CASO_DERIVACION_SALIDA CDS
WHERE (CDS.CASO_TIPO_PRESTACION_FK=1
OR CDS.CASO_TIPO_PRESTACION_FK=2)
--AND CDS.DERIVACION_FECHA_HORA >= CDS.DERIVACION_FECHA_HORA
GROUP BY CDS.CASO_PACIENTE_FK, CDS.DERIVACION_ESPECIALIDAD_COD, /*CDS.DERIVACION_ESTABLECIMIENTO_COD*/
CDS.CASO_NIVEL_ATENCION_TIPO, /*CDS.DERIVACION_FECHA_HORA,*/ CDS.CASO_TIPO_PRESTACION_FK, CDS.DERIVACION_FECHA_HORA,
CDS.SALIDA_FECHA_HORA
HAVING COUNT(*)>1
ORDER BY N_REPETICIONES, CDS.CASO_PACIENTE_FK, CDS.DERIVACION_FECHA_HORA, CDS.SALIDA_FECHA_HORA DESC
THEN Fecha_Salida = 'TRUE';
ELSE FLAG = 0 THEN
Fecha_Salida = 'FALSE'
END LOOP;
END LOOP;
END LOOP;
END LOOP;
RETURN REFTABLE;
RAISE NOTICE 'Hello, %', MYNAME; --Right Here must go the Println (Select field1, field2, etc.....)
--END;
--COMMIT;
END;
END_PROC;

insert into not work in function postgresql

I have the following procedure, when I run it displays all the insertions in console, the field ind_id is increased but does not save any record.
create or replace function renameDescripcionTramite() returns varchar as $$
declare
aguja record;
pajar record;
last_id integer;
begin
for aguja in
select trim(t.tra_descripcion) tra_descripcion from tab_tramite t
join tab_serietramite st on st.tra_id = t.tra_id
group by t.tra_descripcion
order by t.tra_descripcion loop
for pajar in
select u.uni_id,s.ser_id,st.sts_id,t.tra_id,trim(t.tra_descripcion) tra_descripcion
from tab_unidad u join tab_series s on u.uni_id = s.uni_id
join tab_serietramite st on st.ser_id = s.ser_id
join tab_tramite t on t.tra_id = st.tra_id
order by u.uni_id,s.ser_id,t.tra_id loop
if aguja.tra_descripcion = pajar.tra_descripcion then
insert into tab_indexpediente (uni_id,ser_id,tra_id) values (pajar.uni_id,pajar.ser_id,pajar.tra_id);-- returning ind_id into last_id;
--update tab_serietramite set wid = last_id where sts_id = pajar.sts_id;
RAISE NOTICE 'insert into tab_indexpediente (uni_id,ser_id,tra_id) values (%',cast(pajar.uni_id as text)
|| ',' || cast(pajar.ser_id as text) || ',' || cast(pajar.tra_id as text) || ')';
end if;
end loop;
--RAISE NOTICE ' ANTERIOR ES %',aguja;
end loop;
return tra_descripcion;
end;
$$ LANGUAGE plpgsql;
Can someone help me please?
Yes, I did not know that this would affect the procedure.
Thank's laurenz Albe

Any alternatives to using cursor in SQL procedure in Oracle 10g?

I give the SQL few inputs and I need to get all the ID's and their count that doesn't satisfy the required criteria.
I would like to know if there are there any alternatives to using cursor.
DECLARE
v_count INTEGER;
v_output VARCHAR2 (1000);
pc table1%ROWTYPE;
unmarked_ids EXCEPTION;
dynamic_sql VARCHAR (5000);
cur SYS_REFCURSOR;
id pp.id%TYPE;
pos INTEGER;
BEGIN
v_count := 0;
SELECT *
INTO pc
FROM table1
WHERE id = '&ID';
DBMS_OUTPUT.ENABLE;
dynamic_sql :=
'SELECT ID from pp
WHERE ( TO_CHAR(cdate, ''yyyy/mm/dd'') =
TO_CHAR (:a, ''yyyy/mm/dd''))
AND aid IN (SELECT aid FROM ppd WHERE TO_CHAR(cdate, ''yyyy/mm/dd'') =
TO_CHAR (:b, ''yyyy/mm/dd'')
AND cid = :c )
AND cid <> :d';
OPEN cur FOR dynamic_sql USING pc.cdate, pc.cdate, pc.id, pc.id;
LOOP
FETCH cur INTO id;
EXIT WHEN cur%NOTFOUND;
v_count := v_count + 1;
DBMS_OUTPUT.PUT_LINE (' Id:' || id);
END LOOP;
CLOSE cur;
IF (v_count > 0)
THEN
DBMS_OUTPUT.PUT_LINE ( 'Count: ' || v_count || ' SQL: ' || dynamic_sql);
RAISE unmarked_ids;
END IF;
DBMS_OUTPUT.PUT_LINE('SQL ended successfully');
EXCEPTION
WHEN unmarked_ids
THEN
DBMS_OUTPUT.put_line (
'Found ID's that not marked with the current id.');
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (
'No data found in table1 with the current id ' || '&ID');
END;
There are bind variables in the query. One of them is date, there are three more.
The count and ID's are required to be shown which will later be reported.
You could store the rowid in a temporary table along with an index value (0...n) and then use a while loop to go through the index values and join to the real table using the rowid.