J'essaie de renvoyer plusieurs enregistrements en utilisant le type de données RECORD, est-il possible d'ajouter à RECORD et d'ajouter/ajouter une nouvelle valeur à chaque itération à ce RECORD.
c'est-à-dire que je veux ajouter à rec
pour que rec
devienne un ensemble de lignes lorsque la boucle est terminée, que je peux simplement RETOURNER à la fin de ma fonction. Actuellement, je fais cela -
SELECT temp_table.col1, temp_table.col2, temp_table.col3
INTO rec
FROM temp_table
WHERE temp_table.col3 = false;
mon code complet est ici:
CREATE OR REPLACE FUNCTION validation()
RETURNS RECORD AS $$
DECLARE
rec RECORD;
temp_row RECORD;
BEGIN
CREATE TEMPORARY TABLE temp_table (col1 TEXT, col2 INTEGER, col3 BOOLEAN) ON COMMIT DROP;
FOR temp_row IN SELECT * FROM staging.validation
LOOP
RAISE NOTICE 'sql: %', temp_row.sql;
EXECUTE format('INSERT INTO temp_table %s', temp_row.sql);
IF (SELECT DISTINCT temp_table.col3 FROM temp_table WHERE temp_table.col3 = false)=false THEN
RAISE NOTICE 'there is a false value';
SELECT temp_table.col1, temp_table.col2, temp_table.col3
INTO rec
FROM temp_table
WHERE temp_table.col3 = false;
END IF;
END LOOP;
RETURN rec;
END; $$
LANGUAGE plpgsql;
Sortie courant après SELECT validation();
validation
(crea_ddf,8095,f)
Sortie désirée
validation
(crea_ddf,8095,f)
(some_source_system,some_count,f)
(some_other_source_system,some_count,f)
(.....)
La fonction doit renvoyer un SETOF RECORD
Au lieu de RECORD
et avoir un RETURN NEXT
Par ligne au lieu d'un seul RETURN
, comme dans:
CREATE FUNCTION test() RETURNS SETOF RECORD AS $$
DECLARE
rec record;
BEGIN
select 1,2 into rec;
return next rec;
select 3,4 into rec;
return next rec;
END $$ language plpgsql;
Votre interlocuteur:
=> sélectionnez * dans test () comme x (a int, b int); a | b --- + --- 1 | 2 3 | 4 (2 rangées)
Notez que SQL étant fortement et statiquement typé, le pseudo-type RECORD
est difficile à utiliser.
Souvent, il est moins lourd d'utiliser dès le départ un type composite avec une définition complète des noms et du type pour chaque colonne, soit avec la syntaxe TABLE(...)
pour un type anonyme, soit avec CREATE TYPE
pour un type nommé persistant.
Utilisez setof record
Et return next rec
Si vous souhaitez renvoyer plusieurs enregistrements d'une fonction, par exemple:
create or replace function test_function()
returns setof record
language plpgsql as $$
declare
rec record;
begin
for rec in
select i, format('str%s', i), i/2*2 = i
from generate_series(1, 3) i
loop
return next rec;
end loop;
end $$;
Une telle fonction doit être appelée dans la clause FROM avec une liste de définitions de colonnes:
select test_function(); -- NO
ERROR: set-valued function called in context that cannot accept a set
select * from test_function(); -- NO
ERROR: a column definition list is required for functions returning "record"
select * from test_function() as (id int, str text, is_even boolean);
id | str | is_even
----+------+---------
1 | str1 | f
2 | str2 | t
3 | str3 | f
(3 rows)
Une meilleure option consiste à utiliser returns table(...)
et return query
:
drop function if exists test_function();
create or replace function test_function()
returns table (id int, str text, is_even boolean)
language plpgsql as $$
begin
return query
select i, format('str%s', i), i/2*2 = i
from generate_series(1, 3) i;
-- you can use return query multiple times
-- or assign values to columns
-- and return the row:
id = 100;
str = 'extra';
is_even = true;
return next; -- without a parameter
end $$;
Usage:
select test_function(); -- possible but rather impractical
test_function
---------------
(1,str1,f)
(2,str2,t)
(3,str3,f)
(100,extra,t)
(4 rows)
select * from test_function();
id | str | is_even
-----+-------+---------
1 | str1 | f
2 | str2 | t
3 | str3 | f
100 | extra | t
(4 rows)
Ceci est un drapeau rouge ..
validation
.staging
.temp_table.col3
IS FALSE vous retournez à l'utilisateurFaites juste ça ..
WITH t AS ( SELECT true AS runthis FROM staging.validation WHERE col3 IS FALSE )
SELECT *
FROM staging.validation
WHERE t.runthis && col3 = 3
UNION ALL
SELECT *
FROM some_source_system
WHERE t.runthis && some_source_system.col3 = 3
UNION ALL
SELECT *
FROM some_other_source_system
WHERE t.runthis && some_other_source_system.col3 = 3;
Vous pouvez même mettre ça dans un VIEW
si vous voulez
En note
SELECT DISTINCT temp_table.col3
FROM temp_table
WHERE temp_table.col3 = false
Que fait DISTINCT
ici? Il suffit d'en limiter un. En fait, je dirais que c'est encore plus propre.
SELECT true
FROM temp_table
WHERE temp_table.col3 = false
LIMIT 1;
Ensuite, vous n'avez pas besoin de l'étrange = false ) = FALSE