質問全体を書き直す
First()集約関数を探しています。
ここ ほとんど機能するものが見つかりました:
CREATE OR REPLACE FUNCTION public.first_agg ( anyelement, anyelement )
RETURNS anyelement LANGUAGE sql IMMUTABLE STRICT AS $$
SELECT $1;
$$;
-- And then wrap an aggregate around it
CREATE AGGREGATE public.first (
sfunc = public.first_agg,
basetype = anyelement,
stype = anyelement
);
問題は、varchar(n)列がfirst()関数を通過するときに、単純なvarchar(サイズなし)に変換されることです。関数のクエリをRETURNS SETOF anyelementとして返そうとすると、次のエラーが発生します。
エラー:クエリの構造が関数の結果の型と一致しませんEstado de SQL:42804 Detalhe:返される型の文字の型が列2の予想される型の文字の型(40)と一致しません。Contexto:PL/pgSQL関数vsr_table_at_time(anyelement、timestamp without time zone )RETURN QUERYの31行目
同じWikiページに、上記の代わりとなる 関数のCバージョン へのリンクがあります。インストール方法はわかりませんが、このバージョンで問題を解決できるのでしょうか。
一方、上記の関数を変更して、まったく同じタイプの入力列を返す方法はありますか?
DISTINCT ON()
補足として、これはまさに DISTINCT ON()
が行うことです(DISTINCT
と混同しないでください)。
SELECT DISTINCT ON ( expression [, ...] )
は、指定された式がequalと評価される各行セットの最初の行のみを保持します。DISTINCT ON
式は、ORDER BY
と同じルールを使用して解釈されます(上記を参照)。目的の行が最初に表示されるようにするためにORDER BY
を使用しない限り、各セットの「最初の行」は予測できないことに注意してください。例えば
だから、あなたが書くとしたら、
SELECT myFirstAgg(z)
FROM foo
GROUP BY x,y;
それは効果的です
SELECT DISTINCT ON(x,y) z
FROM foo;
-- ORDER BY z;
最初のz
が必要です。 2つの重要な違いがあります。
さらに集約することなく、他の列をまた選択できます。
SELECT DISTINCT ON(x,y) z, k, r, t, v
FROM foo;
-- ORDER BY z, k, r, t, v;
GROUP BY
がないので、できない(実際の)集約を使用することはできません。
CREATE TABLE foo AS
SELECT * FROM ( VALUES
(1,2,3),
(1,2,4),
(1,2,5)
) AS t(x,y,z);
SELECT DISTINCT ON (x,y) z, sum(z)
FROM foo;
-- fails, as you should expect.
SELECT DISTINCT ON (x,y) z, sum(z)
FROM foo;
-- would not otherwise fail.
SELECT myFirstAgg(z), sum(z)
FROM foo
GROUP BY x,y;
ORDER BY
また、私はそれを太字にしなかったが、今は
必要な行が最初に表示されるようにORDER BYを使用しない限り、各セットの「最初の行」は予測できないことに注意してください。例
常にORDER BY
をDISTINCT ON
とともに使用します
多くの人がfirst_value
、 Ordered-Set Aggregate Functions を探していると思います。それをそこに捨てたかっただけです。関数が存在する場合、次のようになります。
SELECT a, b, first_value() WITHIN GROUP (ORDER BY z)
FROM foo
GROUP BY a,b;
しかし、悲しいかなあなたはこれを行うことができます。
SELECT a, b, percentile_disc(0) WITHIN GROUP (ORDER BY z)
FROM foo
GROUP BY a,b;
PostgreSQL 9.4以降でいくつかの機能を使用して、あなたのケースで簡単な方法を見つけました
この例を見てみましょう:
select (array_agg(val ORDER BY i))[1] as first_value_orderby_i,
(array_agg(val ORDER BY i DESC))[1] as last_value_orderby_i,
(array_agg(val))[1] as last_value_all,
(array_agg(val))[array_length(array_agg(val),1)] as last_value_all
FROM (
SELECT i, random() as val
FROM generate_series(1,100) s(i)
ORDER BY random()
) tmp_tbl
それがあなたの場合に役立つことを願っています。
あなたの質問に対する直接的な答えではありませんが、first_value
ウィンドウ関数。それはこのように動作します:
CREATE TABLE test (
id SERIAL NOT NULL PRIMARY KEY,
cat TEXT,
value VARCHAR(2)
date TIMESTAMP WITH TIME ZONE
);
次に、各cat
(カテゴリ)の最初のアイテムが必要な場合は、次のようにクエリします。
SELECT
cat,
first_value(date) OVER (PARTITION BY cat ORDER BY date)
FROM
test;
または:
SELECT
cat,
first_value(date) OVER w
FROM
test
WINDOW w AS (PARTITION BY cat ORDER BY date);