如何将这两个PostgreSQL语句合并为一个用于Rails 3的应用程序?

时间:2011-11-19 08:33:06

标签: sql ruby-on-rails-3 postgresql activerecord rails-postgresql

我想在我的RoR应用程序中组合两个PostgreSQL语句。

第一个SQL语句返回一个链接,其中链接包含两个特定的tag_ids。

SELECT link_id, count(*) as counter
  FROM "totals"
 WHERE "totals"."tag_id" IN (6, 8)
   AND (score > 0)
 GROUP BY link_id
HAVING count(*)=2

RoR ActiveRecord版本:

 links = Total.find_all_by_tag_id(@tag_list, :conditions => ["score > 0"], :select => "link_id, count(*) as counter", :having => "count(*)=#{@tag_list.count}", :group => "link_id").collect(&:link_id).uniq.sort.reverse

第二个SQL语句返回具有特定tag_id得分最高的链接。

SELECT s1.link_id
  FROM totals AS s1
     , (SELECT link_id
              , MAX(score) AS maxscore
          FROM totals
         GROUP BY link_id) as s2
 WHERE s2.link_id = s1.link_id
   and s1.score = s2.maxscore
   AND s1.score > 0 AND s1.tag_id = 6

表的构造如下:

totals:
  link_id : integer
  tag_id : integer
  score : integer

=============================
| link_id  | tag_id | score |
=============================
|    1     |    6   |   5   |
|    1     |    8   |   2   |
|    1     |    3   |   1   |
|    2     |    6   |   6   |
|    2     |    4   |   2   |
|    2     |    8   |   6   |
|    3     |    6   |   5   |
|    3     |    2   |   4   |
|    4     |    2   |   4   |
|    4     |    6   |   1   |
|    4     |    8   |   2   |
=============================

第一个SQL语句将返回link_ids 1, 2 and 4,第二个SQL语句将返回link_ids 1, 2 and 3

如何将两个SQL语句合并为一个,以便获得包含多个选定标记的特定标记的最高分?

合并后的语句应返回link_ids 1 and 2

可以在此处找到DDL和INSERT命令:http://sqlize.com/480glD5Is4

如果可以用RoR ActiveRecord样式或更优化的SQL语句编写,那将是很好的。

非常感谢。

1 个答案:

答案 0 :(得分:1)

  

第一个SQL语句返回链接包含两个链接的链接   具体的tag_ids。

当且仅当在{link_id,tag_id}上存在主键约束或唯一约束时才有效。我添加了约束(有意义),我将为其他人包含CREATE TABLE和INSERT语句。 (你应该这样做。如果你愿意,你可以编辑你的问题并粘贴这些东西。)

create table totals (
  link_id  integer not null,
  tag_id integer not null,
  score integer not null,
  primary key (link_id, tag_id)
);

insert into totals values
(1, 6, 5   ),
(1, 8, 2   ),
(1, 3, 1   ),
(2, 6, 6   ),
(2, 4, 2   ),
(3, 6, 1   ),
(3, 2, 4   ),
(3, 8, 3   ),
(4, 2, 4   ),
(4, 6, 1   ),
(4, 8, 2   );

根据评论重新提出问题,您正在寻找具有

的链接ID号
  • 都标记了ID号6和8,以及
  • 其标记ID 6的得分高于其标记ID 8的得分

首先,很容易看出这两个查询会为您提供

的分数
  • 具有tag_id = 6和
  • 的所有行
  • 所有tag_id = 8

    的行
    select *
    from totals
    where tag_id = 6
    
    select *
    from totals
    where tag_id = 8
    

这很简单。

我们可以使用公用表表达式轻松加入这两个查询。

with score_for_8 as (
  select *
  from totals
  where tag_id = 8
) 
select totals.* 
from totals 
inner join score_for_8
        on score_for_8.link_id = totals.link_id and
           totals.score > score_for_8.score 
where totals.tag_id = 6;

由于这不需要分组,排序或限制结果集,因此它将正确报告关联。

我很确定这仍然不是你想要的,但我不明白你最后的评论。