PostgreSQL: ส่งผ่านตารางเป็นอาร์กิวเมนต์ในฟังก์ชัน


11

ฉันกำลังค้นพบTYPEใน PostgreSQL ฉันมีTABLE TYPEตารางที่ต้องเคารพ (อินเตอร์เฟส) ตัวอย่างเช่น:

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[]
);

ฉันสามารถสร้างตารางโดยใช้เทมเพลตนี้ด้วย:

CREATE TABLE test OF dataset;

ฉันเห็นตัวเลือกมากมายในAPIแต่ฉันทำหายไปเล็กน้อย ฉันต้องการทราบว่าเป็นไปได้หรือไม่ที่จะกำหนดINPUT/OUTPUTพารามิเตอร์ประเภทนี้ให้กับฟังก์ชัน

ขอบอกว่าฉันมีFUNCTIONที่เรียกว่าprocessที่ได้รับตัวอย่างของระเบียนจากชุดข้อมูลTABLE sourceกระบวนการพวกเขาและจากนั้นส่งกลับด้วยเหมือนกันTABLE sinkTYPE

นั่นคือฉันอยากจะรู้ว่ามันเป็นไปได้ที่จะสร้างสิ่งTYPEที่มีลักษณะเช่นนี้หรือไม่:

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

และสามารถเรียกได้ว่าเป็นเช่นนี้:

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

ฉันสงสัยว่ามันเป็นไปได้กับ PostgreSQL และถามว่าจะทำอย่างไร คุณรู้จักใครบ้าง


นี่คือ MWE ของสิ่งที่ฉันพยายามทำ:

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

แต่มันไม่ประสบความสำเร็จมันก็เหมือนกับการรับรู้แหล่งที่มาเป็นคอลัมน์แทนที่จะเป็นSETOF RECORDSกับประเภทของชุดข้อมูล

คำตอบ:


13

พารามิเตอร์ของคุณ_sourceใน MWE ที่เพิ่มเข้ามาจะไม่ถูกอ้างอิงที่ใดก็ได้ ตัวระบุsourceในเนื้อหาของฟังก์ชั่นไม่มีขีดเส้นใต้นำและถูกตีความว่าเป็นชื่อตารางคงที่อย่างอิสระ

ที่สำคัญกว่านั้นมันจะไม่ทำงานเช่นนี้อยู่ดี SQL อนุญาตให้ปรับพารามิเตอร์ค่าในคำสั่ง DML เท่านั้น รายละเอียดในคำตอบที่เกี่ยวข้องนี้:

สารละลาย

คุณยังสามารถทำให้มันใช้งานได้โดยใช้ dynamic SQL EXECUTEในฟังก์ชั่น plpgsql รายละเอียด:

หรือลองค้นหาคำถามและคำตอบที่เกี่ยวข้อง

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 

คุณสามารถทำให้งานนี้เป็นตารางใดก็ได้ :

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!!

คำอธิบายโดยละเอียด:


ขอบคุณสำหรับคำตอบ. ฉันจะตรวจสอบในไม่กี่ชั่วโมง SELECTเพียงแค่ต้องรู้ก่อนการทดสอบเป็นวิธีการแก้ปัญหาของคุณได้รับการยอมรับที่จะเป็นแถวจาก SELECT * FROM process((SELECT * FROM source WHERE cond))ผมหมายถึง
jlandercy

@j: ไม่มีคุณผ่านตารางชื่อ ไม่มีวิธีการส่งผ่านตารางเอง (ไม่มีตัวแปรตาราง) มีหลายวิธีรอบ ๆ มัน ที่เกี่ยวข้อง: stackoverflow.com/a/27853965/939860หรือstackoverflow.com/a/31167928/939860 ในการทำงานกับผลลัพธ์ของแบบสอบถามฉันจะใช้เคอร์เซอร์หรือตารางชั่วคราว ...
Erwin Brandstetter

0

สิ่งนี้จะทำสิ่งที่คุณต้องการโดยไม่ต้องใช้SQL แบบไดนามิกใด ๆ:

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

เท่าที่ฉันสามารถบอกได้ (หลังจาก googeling อย่างกว้างขวางเพราะฉันมีปัญหาเดียวกัน) คุณไม่สามารถส่งผ่านตารางไปยังฟังก์ชันได้โดยตรง

อย่างไรก็ตามดังที่แสดงไว้คุณสามารถแปลงตารางเป็นอาร์เรย์[]ของประเภทที่กำหนดเองที่ประกอบด้วยประเภทพื้นฐานหลายประเภท (คล้ายกับคำจำกัดความของตาราง)

จากนั้นคุณสามารถส่งผ่านอาร์เรย์นั้นและกลับเข้าไปในตารางโดยไม่สนใจเมื่อคุณอยู่ในฟังก์ชัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.