CREATE OR REPLACE FUNCTION search_by_tags(tags varchar[])
RETURNS TABLE (id_course integer, name text, tag_ct integer) AS
$func$
SELECT id_course, c.name, ct.tag_ct
FROM (
SELECT tc.id_course, count(*)::int AS tag_ct
FROM unnest($1) x(tag)
JOIN tagcourse tc USING (tag)
GROUP BY 1 -- first aggregate ..
) AS ct
JOIN course c USING (id_course) -- .. then join
ORDER BY ct.tag_ct DESC -- more columns to break ties?
$func$ LANGUAGE sql;
@Clodoaldo で既に実証されているunnest()
ように、入力配列からテーブルを生成するために使用します。
これにはplpgsqlは必要ありません。単純な SQL 関数を使用するとより簡単になります。
後者は (plpgsql とは異なり) SQL 関数の PostgreSQL 9.2+ でのみ有効であるため、unnest($1)
代わりに (位置パラメーターを使用して) を使用します。ここでマニュアルを引用します:unnest(tags)
古い数値アプローチでは、引数は次の構文を使用して参照されます$n
。$1
最初の入力引数を参照$2
し、2 番目の入力引数などを参照します。これは、特定の引数が名前で宣言されているかどうかに関係なく機能します。
count()
戻りますbigint
。宣言された戻り値の型と一致するようにキャストするint
か、最初から返される列を宣言する必要がありbigint
ます。
の代わりにUSING
(equi-joins):を使用して、構文を少し単純化する絶好の機会です。USING (tag)
ON tc.tag = c.tag
通常は、最初に集計してから別のテーブルに結合する方が高速です。必要な結合操作を減らします。コメントの @Clodoaldo の
質問に従って、違いを示すSQL Fiddleを次に示します。
OTOH、結合後に集計する場合、サブクエリは必要ありません。短くなりますが、おそらく遅くなります:
SELECT c.id_course, c.name, count(*)::int AS tag_ct
FROM unnest($1) x(tag)
JOIN tagcourse tc USING (tag)
JOIN course c USING (id_course)
GROUP BY 1
ORDER BY 3 DESC; -- more columns to break ties?