Как объединить эти два оператора PostgreSQL в один для приложения Rails 3? - PullRequest
2 голосов
/ 19 ноября 2011

У меня есть два оператора PostgreSQL, которые я хотел бы объединить в своем приложении RoR.

Первый оператор SQL возвращает ссылку, в которой ссылка содержит два специальных тега_id.

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 возвращает ссылки, которые имеют наивысшую оценку определенного тега_ид.

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 Ответ

1 голос
/ 19 ноября 2011

Первый оператор 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   );

Перефразируя вопрос, основываясь на комментариях, вы ищете номера идентификаторов ссылок, которые имеют

  • оба идентификатора тега с номерами 6 и 8 и
  • , чей счет для идентификатора тега 6 выше, чем их счет для идентификатора тега 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;

Поскольку для этого не требуется группировать, упорядочивать или ограничивать набор результатов, он будет правильно сообщать о связях.

Я почти уверен, что это не совсем то, что вы ищете, но я не понимаю ваш последний комментарий.

...