Kullanım RETURN QUERY
:
CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
RETURNS TABLE (txt text -- also visible as OUT parameter inside function
, cnt bigint
, ratio bigint) AS
$func$
BEGIN
RETURN QUERY
SELECT t.txt
, count(*) AS cnt -- column alias only visible inside
, (count(*) * 100) / _max_tokens -- I added brackets
FROM (
SELECT t.txt
FROM token t
WHERE t.chartype = 'ALPHABETIC'
LIMIT _max_tokens
) t
GROUP BY t.txt
ORDER BY cnt DESC; -- potential ambiguity
END
$func$ LANGUAGE plpgsql;
Aramak:
SELECT * FROM word_frequency(123);
Açıklama:
Öyle çok açıkça basitçe kayıt olarak deklare daha dönüş türünü tanımlamak için daha pratik. Bu şekilde, her işlev çağrısıyla bir sütun tanımı listesi sağlamanız gerekmez. RETURNS TABLE
bunu yapmanın bir yolu. Başkaları da var. OUT
Parametrelerin veri türleri , sorgu tarafından döndürülenle tam olarak eşleşmelidir.
OUT
Parametreler için isimleri dikkatlice seçin . Fonksiyon gövdesinde hemen hemen her yerde görülebilirler. Çakışmaları veya beklenmedik sonuçları önlemek için aynı ada sahip tablo niteliğinde sütunlar. Bunu örneğimdeki tüm sütunlar için yaptım.
Ancak parametre ile aynı adın sütun diğer adı arasındaki olası adlandırma çakışmasına dikkat edin . Bu özel durumda ( ) Postgres, her iki şekilde de parametre üzerinde sütun diğer adını kullanır . Yine de bu, diğer bağlamlarda belirsiz olabilir. Herhangi bir karışıklığı önlemenin çeşitli yolları vardır:OUT
cnt
RETURN QUERY SELECT ...
OUT
- SEÇ listedeki öğenin sıralı konumunu kullanın:
ORDER BY 2 DESC
. Misal:
- İfadeyi tekrarlayın
ORDER BY count(*)
.
- (Burada uygulanamaz.) Yapılandırma parametresini ayarlayın
plpgsql.variable_conflict
veya #variable_conflict error | use_variable | use_column
işlevdeki özel komutu kullanın . Görmek:
Sütun adları olarak "metin" veya "sayma" kullanmayın. Her ikisinin de Postgres'te kullanımı yasaldır, ancak "sayı", standart SQL'de ayrılmış bir sözcüktür ve temel bir işlev adı ve "metin", temel bir veri türüdür. Kafa karıştırıcı hatalara yol açabilir. Örneklerimde txt
ve kullanıyorum cnt
.
Başlıkta eksik ;
ve düzeltilmiş bir sözdizimi hatası eklendi . (_max_tokens int)
Değil (int maxTokens)
- yazın sonra isim .
Tamsayı bölme ile çalışırken, yuvarlama hatasını en aza indirmek için önce çarpıp sonra bölmek daha iyidir. Daha da iyisi: ile çalışın numeric
(veya kayan nokta türüyle). Aşağıya bakınız.
Alternatif
Bu benim ne düşünüyorum sorgu aslında (bir hesaplama gibi görünmelidir simge başına nispi pay ):
CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
RETURNS TABLE (txt text
, abs_cnt bigint
, relative_share numeric) AS
$func$
BEGIN
RETURN QUERY
SELECT t.txt, t.cnt
, round((t.cnt * 100) / (sum(t.cnt) OVER ()), 2) -- AS relative_share
FROM (
SELECT t.txt, count(*) AS cnt
FROM token t
WHERE t.chartype = 'ALPHABETIC'
GROUP BY t.txt
ORDER BY cnt DESC
LIMIT _max_tokens
) t
ORDER BY t.cnt DESC;
END
$func$ LANGUAGE plpgsql;
İfade sum(t.cnt) OVER ()
bir pencere işlevidir . Sen olabilir bir kullanmak CTE oldukça, ancak bir alt sorgu bunun gibi basit vakalarda tipik ucuzdur - alt sorgunun yerine.
Parametrelerle çalışırken veya ( parametrelerin örtük kullanımını sağlayan ) son bir açık RETURN
ifade gerekli değildir (ancak buna izin verilir ).OUT
RETURNS TABLE
OUT
round()
iki parametre ile yalnızca numeric
türler için çalışır . count()
alt sorguda bir bigint
sonuç üretir ve bir sum()
over bu bigint
bir numeric
sonuç üretir , böylece bir numeric
sayıyla otomatik olarak ilgileniriz ve her şey yerine oturur.