PostgreSQL: ফাংশনে আর্গুমেন্ট হিসাবে টেবিলটি পাস করুন


11

আমি TYPEপোস্টগ্রিজ এসকিউএলে আবিষ্কার করছি । আমার 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;

আমি অনেক অপশন আছে দেখা যায় এপিআই , কিন্তু আমি একটু হারিয়ে নই। আমি জানতে চাই যে INPUT/OUTPUTপ্যারামিটারগুলিকে এই ধরণের নির্ধারণ করা সম্ভব কিনা ।

ধরা যাক যে আমার কাছে একটি কল রয়েছে FUNCTIONযা processএকটি ডেটাসেট থেকে রেকর্ডের নমুনা গ্রহণ করে TABLE source, সেগুলি প্রক্রিয়া করে এবং তারপরে একইটি দিয়ে একটি ফেরত TABLE sinkদেয় TYPE

এটিই আমি জানতে চাই যে এটির TYPEমতো আচরণ করে এমন কোনও তৈরি করা সম্ভব কিনা :

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

এবং এটিকে এভাবে বলা যেতে পারে:

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

আমি অবাক হই যে পোস্টগ্র্রেএসকিউএল দিয়ে এটি সম্ভব, এবং কীভাবে এটি করা যায় তা জিজ্ঞাসা করুন। আপনারা কি জানেন?


আমি যা করার চেষ্টা করছি তার একটি এমডব্লিউই এখানে:

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যুক্ত হওয়া এমডব্লিউইতে আপনার প্যারামিটারটি কোথাও রেফারেন্স করা হয়নি। sourceফাংশন বডিটিতে শনাক্তকারীটির কোনও শীর্ষস্থানীয় আন্ডারস্কোর নেই এবং ধীরে ধীরে টেবিলের নামটি স্বাধীনভাবে ব্যাখ্যা করা হয়।

আরও গুরুত্বপূর্ণ বিষয়, এটি যাইহোক এটির মতো কাজ করবে না। এসকিউএল কেবলমাত্র ডিএমএল স্টেটমেন্টগুলিতে মানগুলি প্যারামিটারাইজ করতে দেয় । এই সম্পর্কিত উত্তরে বিশদ:

সমাধান

আপনি এখনও EXECUTEএকটি পিএলপিএলএসকিএল ফাংশন সহ গতিশীল এসকিউএল ব্যবহার করে এটি কাজ করতে পারেন । বিবরণ:

অথবা সম্পর্কিত প্রশ্ন এবং উত্তরগুলির জন্য এই অনুসন্ধানটি ব্যবহার করে দেখুন

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

@ জ: না, আপনি একটি টেবিলের নাম পাস করেছেন । কোনও টেবিল নিজেই পাস করার কোনও উপায় নেই (কোনও টেবিল ভেরিয়েবল নেই)। এর চারপাশে বেশ কয়েকটি উপায় রয়েছে। সম্পর্কিত: স্ট্যাকওভারফ্লো . com / a / 27853965 / 939860 বা স্ট্যাকওভারফ্লো . com / a / 31167928 / 939860 । কোনও প্রশ্নের ফলাফল নিয়ে কাজ করতে আমি একটি কার্সার বা একটি অস্থায়ী টেবিল ব্যবহার করব ...
এরউইন ব্র্যান্ডসেটেটার

0

এটি কোনও গতিশীল এসকিউএল প্রয়োজন ছাড়াই আপনি যা করতে চান তা করবে :

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

আমি যতদূর বলতে পারি (গুগলিং এক্সটেনসিভালি করার পরে, কারণ আমার একই সমস্যা ছিল) আপনি কোনও ফাংশনে সরাসরি কোনও টেবিল পাস করতে পারবেন না।

যাইহোক, প্রদর্শিত হিসাবে, আপনি একটি টেবিলটি []একটি কাস্টম টাইপের একটি অ্যারেতে রূপান্তর করতে পারেন যা বেশ কয়েকটি মৌলিক ধরণের (একটি টেবিলের সংজ্ঞা অনুসারে) থাকে।

তারপরে আপনি সেই অ্যারেটি পাস করতে পারেন এবং ফাংশনে আসার পরে এটি কোনও টেবিলে ফিরিয়ে আনতে পারেন না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.