PostgreSQL: Truyền bảng làm đối số trong hàm


11

Tôi đang khám phá TYPEtrong PostgreSQL. Tôi có một TABLE TYPEbảng mà một số bảng phải tôn trọng (giao diện). Ví dụ:

CREATE TYPE dataset AS(
    ChannelId INTEGER
   ,GranulityIdIn INTEGER
   ,GranulityId INTEGER
   ,TimeValue TIMESTAMP
   ,FloatValue FLOAT
   ,Status BIGINT
   ,QualityCodeId INTEGER
   ,DataArray FLOAT[]
   ,DataCount BIGINT
   ,Performance FLOAT
   ,StepCount INTEGER
   ,TableRegClass regclass
   ,Tags TEXT[]
   ,WeightedMean FLOAT
   ,MeanData FLOAT
   ,StdData FLOAT
   ,MinData FLOAT
   ,MaxData FLOAT
   ,MedianData FLOAT
   ,Percentiles FLOAT[]
);

Tôi có thể tạo bảng bằng mẫu này với:

CREATE TABLE test OF dataset;

Tôi đã thấy nhiều tùy chọn trong API , nhưng tôi hơi lạc lõng. Tôi muốn biết nếu có thể gán loại này cho các INPUT/OUTPUTtham số chức năng .

Giả sử rằng tôi có một cuộc FUNCTIONgọi processnhận một mẫu hồ sơ từ một tập dữ liệu TABLE source, xử lý chúng và sau đó trả về một TABLE sinkcùng một TYPE.

Đó là tôi muốn biết liệu có thể tạo ra một TYPEhành vi như thế này không:

CREATE FUNCTION process(
    input dataset
) RETURNS dataset
AS ...

Và điều đó có thể được gọi như thế này:

SELECT
    *
FROM
    source, process(input := source) AS sink;

Tôi tự hỏi rằng điều đó là có thể với PostgreSQL và hỏi làm thế nào để làm điều đó. Có ai trong số bạn biết?


Đây là một MWE về những gì tôi đang cố gắng làm:

DROP TABLE IF EXISTS source;
DROP FUNCTION IF EXISTS process(dataset);
DROP TYPE dataset;

CREATE TYPE dataset AS (
    id INTEGER
   ,t  TIMESTAMP
   ,x  FLOAT
);


CREATE TABLE source OF dataset;
ALTER TABLE source ADD PRIMARY KEY(Id);
INSERT INTO source VALUES
    (1, '2016-01-01 00:00:00', 10.0)
   ,(2, '2016-01-01 00:30:00', 11.0)
   ,(3, '2016-01-01 01:00:00', 12.0)
   ,(4, '2016-01-01 01:30:00',  9.0)
   ;

CREATE OR REPLACE FUNCTION process(
    _source dataset
)
RETURNS SETOF dataset
AS
$BODY$
SELECT * FROM source;
$BODY$
LANGUAGE SQL;

SELECT * FROM process(source);

Nhưng nó không thành công, nó giống như nguồn được coi là một cột thay vì một SETOF RECORDSloại dữ liệu.

Câu trả lời:


13

Tham số của bạn _sourcetrong MWE được thêm vào không được tham chiếu ở bất cứ đâu. Mã định danh sourcetrong thân hàm không có dấu gạch dưới hàng đầu và được hiểu là tên bảng không đổi một cách độc lập.

Quan trọng hơn, dù sao nó cũng không hoạt động như thế này. SQL chỉ cho phép tham số hóa các giá trị trong các câu lệnh DML. Chi tiết trong câu trả lời liên quan này:

Giải pháp

Bạn vẫn có thể làm cho nó hoạt động bằng cách sử dụng SQL động với EXECUTEchức năng plpgsql. Chi tiết:

Hoặc thử tìm kiếm này cho các câu hỏi và câu trả lời liên quan

CREATE TYPE dataset AS (id integer, t timestamp, x float);
CREATE TABLE source OF dataset (PRIMARY KEY(Id));  -- add constraints in same command

INSERT INTO source VALUES
    (1, '2016-01-01 00:00:00', 10.0)
   ,(2, '2016-01-01 00:30:00', 11.0);

CREATE OR REPLACE FUNCTION process(_tbl regclass)
  RETURNS SETOF dataset AS
$func$
BEGIN
RETURN QUERY EXECUTE 'SELECT * FROM ' || _tbl;
END
$func$  LANGUAGE plpgsql;

SELECT * FROM process('source');  -- table name as string literal 

Bạn thậm chí có thể làm cho công việc này cho bất kỳ bảng nào:

CREATE OR REPLACE FUNCTION process2(_tbl anyelement)
  RETURNS SETOF anyelement AS
$func$
BEGIN
RETURN QUERY EXECUTE 'SELECT * FROM ' || pg_typeof(_tbl);
END
$func$  LANGUAGE plpgsql;

SELECT * FROM process2(NULL::source);  -- note the call syntax!!

Giải thích chi tiết:


Cảm ơn đã trả lời. Il sẽ kiểm tra nó trong vài giờ. Chỉ cần biết trước khi thử nghiệm, là giải pháp của bạn chấp nhận nhận hàng từ as SELECT. Ý tôi là SELECT * FROM process((SELECT * FROM source WHERE cond)).
jlandercy

@j: Không, bạn vượt qua một tên bảng . Không có cách nào để vượt qua chính bảng (không có biến bảng). Có một số cách xung quanh nó. Liên quan: stackoverflow.com/a/27853965/939860 hoặc stackoverflow.com/a/31167928/939860 . Để làm việc với kết quả của một truy vấn, tôi sẽ sử dụng một con trỏ hoặc bảng tạm thời ...
Erwin Brandstetter

0

Điều này sẽ làm những gì bạn muốn mà không cần bất kỳ SQL động nào :

drop table if exists source cascade;
drop function if exists process(dataset) cascade;
drop type if exists dataset cascade;

create type dataset as (
    id integer
   ,t  timestamp
   ,x  float
);

create table source of dataset;
alter table source add primary key(id);
insert into source values
   (1, '2016-01-01 00:00:00', 10.0)
 , (2, '2016-01-01 00:30:00', 11.0)
;

create or replace function process(
    x_source dataset[]
)
returns setof dataset
as
$body$
select * from unnest(x_source);
$body$
language sql;

select *
from
  process(
    array(
      select
        row(id, t, x)::dataset
      from source
    )
  );

Theo như tôi có thể nói (sau khi googeling mở rộng, bởi vì tôi có cùng một vấn đề), bạn không thể chuyển một bảng trực tiếp đến một chức năng.

Tuy nhiên, như được hiển thị, bạn có thể chuyển đổi một bảng thành một mảng []của một loại tùy chỉnh bao gồm một số loại cơ bản (tương tự như một định nghĩa bảng).

Sau đó, bạn có thể chuyển mảng đó và hủy bỏ nó trở lại vào bảng khi bạn đang ở trong hàm.

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.