PostgreSQL - 按数组排序

时间:2013-03-27 16:40:24

标签: sql postgresql sql-order-by aggregate set-returning-functions

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

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....

2 个答案:

答案 0 :(得分: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;
  

在旧的数值方法中,使用。引用参数   语法$n$1引用第一个输入参数$2到第二个,   等等。无论具体论证是什么,这都将起作用   用名字声明。

  • count()返回bigint。您需要将其强制转换为int以匹配声明的返回类型,或者将返回的列声明为bigint以开始。

  • 使用USING(等连接)简化语法的完美场合:USING (tag)而不是ON tc.tag = c.tag

  • 首次聚合通常会更快,然后加入另一个表。减少所需的连接操作 根据{{​​3}}的问题,这里有@Clodoaldo in the comments来证明其差异。

  • 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?

答案 1 :(得分: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;