PostgreSQL: İşlevde argüman olarak tabloyu geç


11

TYPEPostgreSQL'de keşfediyorum . Ben bir TABLE TYPEbazı tablo (arayüz) saygı gerekir. Örneğin:

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

Bu şablonu kullanarak tablo oluşturabilirim:

CREATE TABLE test OF dataset;

API'de birçok seçenek gördüm , ancak biraz kayboldum. Bu tür işlev INPUT/OUTPUTparametrelerine atanmanın mümkün olup olmadığını bilmek istiyorum .

Diyelim ki, bir veri kümesinden kayıtların bir örneğini alan , bunları işleyen ve daha sonra aynı olan bir döndüren bir FUNCTIONçağrı processvar .TABLE sourceTABLE sinkTYPE

Yani TYPEböyle davranan bir oluşturmak mümkün olup olmadığını bilmek istiyorum:

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

Ve buna şöyle denilebilir:

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

PostgreSQL ile mümkün olduğunu merak ediyorum ve nasıl yapılacağını sorun. Biriniz biliyor mu?


İşte yapmaya çalıştığım bir 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);

Ancak başarılı olmaz, kaynak SETOF RECORDSveri kümesi türünde bir yerine bir sütun olarak algılanır .

Yanıtlar:


13

_sourceEklenen MWE'deki parametrenize hiçbir yerde referans verilmiyor. sourceİşlev gövdesindeki tanımlayıcının önünde alt çizgi yoktur ve bağımsız olarak sabit tablo adı olarak yorumlanır.

Daha da önemlisi, yine de böyle çalışmaz. SQL, yalnızca DML ifadelerindeki değerleri parametreleştirmeye izin verir . Bu cevaptaki ayrıntılar:

Çözüm

Hala EXECUTEplpgsql işlevinde dinamik SQL kullanarak çalışmasını sağlayabilirsiniz . Detaylar:

Veya ilgili soru ve cevaplar için bu aramayı deneyin

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 

Bu çalışmayı herhangi bir tablo için bile yapabilirsiniz :

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

Detaylı açıklama:


Cevabın için teşekkür ederim. Birkaç saat içinde kontrol edeceğim. Test etmeden önce bilmek, çözümünüzün satırları almayı kabul etmesidir SELECT. Yani SELECT * FROM process((SELECT * FROM source WHERE cond)).
jlandercy

@j: Hayır, bir tablo adı geçiyorsun . Bir tablonun kendisini geçirmenin bir yolu yoktur (tablo değişkeni yok). Etrafında birkaç yol var. İlgili: stackoverflow.com/a/27853965/939860 veya stackoverflow.com/a/31167928/939860 . Bir sorgu sonucu üzerinde çalışmak için bir imleç veya geçici bir tablo kullanacağım ...
Erwin Brandstetter

0

İstediğin bu yapacak olmadan herhangi gerek dinamik 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
    )
  );

Anlayabildiğim kadarıyla (yoğun bir şekilde googeling sonra, aynı sorun vardı çünkü) bir tabloya doğrudan bir fonksiyona geçemezsiniz.

Ancak, gösterildiği gibi, bir tabloyu []birkaç temel türden oluşan (tablo tanımına benzer) özel türden bir diziye dönüştürebilirsiniz .

Sonra bu diziyi geçirebilir ve fonksiyona girdikten sonra bir tabloya geri döndürebilirsiniz.

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.