6

我有 2 个表 - course 包含课程的 ID 和名称,tagCourse 包含每个课程的标签。

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

我想编写一个函数,通过给定的标签数组搜索课程并返回按匹配标签数量排序的课程。但是我不知道如何正确有效地编写它。请帮我。

IE。

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;
  • 用于unnest()从您的输入数组生成一个表格,就像@Clodoaldo 已经演示的那样

  • 为此,您不需要 plpgsql。使用简单的 SQL 函数更简单。

  • 我使用unnest($1)(with positional parameter) 而不是unnest(tags),因为后者仅对 SQL 函数中的 PostgreSQL 9.2+ 有效(与 plpgsql 不同)。我在这里引用手册

在较旧的数值方法中,使用语法引用参数$n$1指第一个输入参数,$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 回答