Làm cách nào tôi có thể trả lại nhiều hàng bản ghi trong PL / pgSQL


12

Tôi đang cố gắng trả về nhiều bản ghi bằng cách sử dụng loại dữ liệu RECORD, có cách nào để tôi có thể thêm vào RECORD và thêm / nối một giá trị mới với mỗi lần lặp vào RECORD này.

nghĩa là, tôi muốn thêm vào recđể rectrở thành một tập hợp các hàng khi vòng lặp kết thúc, mà tôi chỉ có thể TRẢ LẠI ở cuối chức năng của mình. Hiện tại, tôi đang làm điều này -

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

mã đầy đủ của tôi ở đây:

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;

Sản lượng hiện tại sau SELECT validation();

validation
(crea_ddf,8095,f)

Sản phẩm chất lượng

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

@EvanCarroll Xin chào Evan, đó là câu hỏi của tôi, mà tôi cũng đã đăng ở đó ... chỉ trong trường hợp nếu ai đó bỏ lỡ nó ở đây.
hky404

Tôi không chắc chắn những gì bạn đang cố gắng làm, bạn có thể giải thích thêm một chút không?
Evan Carroll

1
@ hky404: vui lòng không đăng bài chéo; Điều đó chỉ gây ra sự trùng lặp của những nỗ lực.
Martijn Pieters

Câu trả lời:


12

Hàm cần trả về một SETOF RECORDthay vì RECORDvà có một RETURN NEXThàng thay vì một hàng RETURN, như trong:

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;

Người gọi:

=> chọn * từ test () là x (a int, b int);
 một | b
--- + ---
 1 | 2
 3 | 4
(2 hàng)

Lưu ý rằng SQL được gõ mạnh và tĩnh, loại RECORDgiả rất khó để làm việc.
Thông thường, nó ít cồng kềnh hơn khi sử dụng ngay từ khi bắt đầu một loại hỗn hợp với định nghĩa đầy đủ về tên và loại cho mỗi cột, với TABLE(...)cú pháp cho loại ẩn danh hoặc với CREATE TYPEloại có tên liên tục.


8

Sử dụng setof recordreturn next recnếu bạn muốn trả về nhiều bản ghi từ một hàm, ví dụ:

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

Một hàm như vậy cần được gọi trong mệnh đề TỪ với danh sách định nghĩa cột:

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)

Một lựa chọn tốt hơn là sử dụng returns table(...)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 $$;

Sử dụng:

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

Đây là một lá cờ đỏ ..

  1. Bạn có một cái bàn validation.
  2. Bạn di chuyển các hàng vào một bảng tạm thời staging.
  3. Bất kỳ hàng nào có temp_table.col3IS FALSE bạn trả lại cho người dùng
  4. Cùng với bất kỳ hàng nào khác trong danh sách các bảng được chỉ định trong đó cột đó là sai.
  5. Sau đó, bạn thả bảng tạm thời (trên cam kết)

Chỉ cần làm điều này ..

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;

Bạn thậm chí có thể đặt nó trong một VIEWnếu bạn muốn

Như một lưu ý phụ

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

Không gì DISTINCTđây làm gì? Chỉ cần làm GIỚI HẠN một. Trong thực tế, tôi sẽ tranh luận rằng điều này thậm chí còn sạch hơn.

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

Sau đó, bạn không cần sự kỳ lạ = false ) = FALSE

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.