PL / pgSQL'de birden çok kayıt sırasını nasıl döndürebilirim


14

RECORD veri türünü kullanarak birden fazla kayıt döndürmeye çalışıyorum, KAYIT eklemek ve bu KAYIT her yineleme ile yeni bir değer eklemek bir yolu var.

olduğunu, ben eklemek istediğiniz recşekilde recdöngü bittiğinde, satır kümesi haline gelir benim işlevi sonunda sadece DÖNÜŞ can. Şu anda bunu yapıyorum -

SELECT temp_table.col1, temp_table.col2, temp_table.col3
      INTO rec
      FROM temp_table
      WHERE temp_table.col3 = false;

tam kodum burada:

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;

Akım çıkışı SELECT validation();

validation
(crea_ddf,8095,f)

Istenilen çıktı

validation
(crea_ddf,8095,f)
(some_source_system,some_count,f)
(some_other_source_system,some_count,f)
(.....)

@EvanCarroll Merhaba Evan, bu benim de orada gönderdiğim sorum ... Buradaki birisi onu kaçırırsa.
hky404

Ne yapmaya çalıştığınızdan emin değilim, biraz daha açıklayabilir misiniz?
Evan Carroll

1
@ hky404: lütfen çapraz gönderi yapmayın; bu sadece çabaların tekrarlanmasına neden olur.
Martijn Pieters

Yanıtlar:


14

İşlevin bir SETOF RECORDyerine dönmesi RECORDve tek RETURN NEXTbaşına yerine satır başına bir tane RETURNolması gerekir:

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;

Arayan:

=> test () 'den x (a int, b int) olarak * seçin;
 a | b
--- + ---
 1 | 2
 3 | 4
(2 sıra)

SQL'in güçlü ve statik olarak yazıldığını, RECORDsözde türle çalışmanın zor olduğunu unutmayın.
Çoğu zaman, TABLE(...)anonim bir türün sözdizimi ile veya CREATE TYPEkalıcı bir adlandırılmış tür için , her bir sütun için tam ad ve tür tanımına sahip kompozit bir türü en baştan kullanmak daha az zahmetlidir .


8

Bir işlevden birden fazla kayıt döndürmek istiyorsanız setof recordve tuşlarını kullanın return next rec, örnek:

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 $$;

Böyle bir işlevin FROM yan tümcesinde bir sütun tanım listesiyle çağrılması gerekir:

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)

Daha iyi bir seçenek kullanmak returns table(...)ve 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 $$;

Kullanımı:

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)

1

Bu bir kırmızı bayrak ..

  1. Masan var validation.
  2. Satırları geçici tabloya taşırsınız staging.
  3. temp_table.col3Kullanıcıya döndürdüğünüz IS FALSE olan satırlar
  4. Bu sütunun yanlış olduğu belirtilen bir tablo listesindeki diğer satırlarla birlikte.
  5. Sonra geçici tabloyu düşürürsünüz

Sadece bunu yap ..

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;

Hatta o koyabilirsiniz VIEWİstersen

Yan not olarak

SELECT DISTINCT temp_table.col3
FROM temp_table
WHERE temp_table.col3 = false

DISTINCTBurada ne yapar ? Sadece bir tane LIMIT. Aslında bunun daha da temiz olduğunu iddia ediyorum.

SELECT true
FROM temp_table
WHERE temp_table.col3 = false
LIMIT 1;

O zaman tuhaflığa ihtiyacın yok = false ) = FALSE

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.