6

コースのIDと名前を含むコースと、各コースのタグを含むtagCourseの2つのテーブルがあります。

course                    tagcourse
------------            ----------------
PK id_course            PK tag
   name                 PK, FK id_course

指定されたタグの配列でコースを検索し、一致するタグの数で並べ替えてコースを返す関数を書きたいと思います。ただし、正しく効率的な方法で記述する方法がわかりません。私を助けてください。

すなわち。

CREATE OR REPLACE FUNCTION searchByTags(tags varchar[])
RETURNS SETOF.....
  RETURN QUERY SELECT * FROM course c INNER JOIN tagcourse tc ON c.id_course = tc.id_course
  WHERE ???  ORDER BY ???

END....
4

2 に答える 2

4
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?
于 2013-03-28T05:00:09.397 に答える
0
create or replace function searchByTags(tags varchar[])
returns table (id_course integer, name text, quantitiy integer)
as $$
    select *
    from (
        select c.id_course, c.name, count(*) quantity
        from
            course c
            inner join
            tagcourse tc on c.id_course = tc.id_course
            inner join
            unnest(tags) s(tag) on s.tag = tc.tag
        group by c.id_course, c.name
    ) s
    order by quantity desc, name
    ;
$$ language sql;
于 2013-03-27T16:59:42.367 に答える