2014-11-14 4 views
1

У меня есть таблицы со статьями и пользователями, у обоих есть много-много картирование на третьей таблице - читается.Дополнительные условия в JOIN

Что я пытаюсь сделать здесь, это получить все непрочитанные статьи для конкретного пользователя (user_id нет в таблице reads). В моем запросе есть все статьи, но те, которые читаются, отмечены, что если я могу отфильтровать их (поле user_id содержит идентификатор соответствующего пользователя).

У меня есть SQL запрос следующим образом:

SELECT articles.id, reads.user_id 
FROM articles 
LEFT JOIN 
reads 
ON articles.id = reads.article_id AND reads.user_id = 9 
ORDER BY articles.last_update DESC LIMIT 5; 

что дает следующее:

articles.id | reads.user_id 
-------------------+----------------- 
57125839   |  9 
57065456   | 
56945065   | 
56945066   | 
56763090   | 
(5 rows) 

Это нормально. Это то, чего я хочу.

Я хотел бы получить тот же результат в Catalyst, используя мою модель статьи, но я не могу найти никакой возможности добавить условия в предложение JOIN.

Вы знаете, как добавить AND X = Y в DBIx JOIN?

Я знаю, что это можно сделать с помощью специального источника и виртуального представления, но у меня есть другие вопросы, которые могут извлечь выгоду из него, и я бы хотел избежать создания виртуального представления для каждого из них.

Спасибо, Canto

+0

Вы пытались добавить его как «стандарт», где п? –

+1

Да. «Стандартное» предложение where будет фильтровать только те статьи, которые читаются пользователем (существует в таблице чтения). В нем не будут отображаться статьи, в которых соответствующая запись в таблице будет NULL. Использование AND с LEFT JOIN предоставит мне ВСЕ статьи. Поле User_id будет установлено, если статья прочитана, если не будет NULL. – canto

+0

Вы не можете использовать условие 'AND reads.user_id = 9' в запросе, если хотите получить статьи с' reads.user_id = NULL'. – krokodilko

ответ

1

Я получил решение.

Это не прямой, но это лучше, чем виртуальный вид.

http://search.cpan.org/dist/DBIx-Class/lib/DBIx/Class/Relationship/Base.pm#condition

Выше описано, как использовать условие в РЕГИСТРИРУЙТЕСЬ положение. Однако в этом случае мне нужна переменная в тех условиях, которая по умолчанию недоступна в модели. Так что, обойдя немного концепции модели и введя в нее переменную, мы имеем следующее.

В файле модели

our $USER_ID; 
__PACKAGE__->has_many(
    pindols => "My::MyDB::Result::Read", 
    sub { 
     my $args = shift; 

     die "no user_id specified!" unless $USER_ID; 

     return ({ 
      "$args->{self_alias}.id" => { -ident => "$args->{foreign_alias}.article_id" }, 
      "$args->{foreign_alias}.user_id" => { -ident => $USER_ID }, 
     }); 

    } 
); 

контроллер

$My::MyDB::Result::Article::USER_ID = $c->user->id; 
$articles = $channel->search(
    { "pindols.user_id" => undef } , 
    { 
     page => int($page), 
     rows => 20, 
     order_by => 'last_update DESC', 
     prefetch => "pindols" 
    } 
); 

загрузит все непрочитанные статьи и выход следующих SQL.

SELECT me.id, me.url, me.title, me.content, me.last_update, me.author, me.thumbnail, pindols.article_id, pindols.user_id FROM (SELECT me.id, me.url, me.title, me.content, me.last_update, me.author, me.thumbnail FROM articles me LEFT JOIN reads pindols ON (me.id = pindols.article_id AND pindols.user_id = 9) WHERE (pindols.user_id IS NULL) GROUP BY me.id, me.url, me.title, me.content, me.last_update, me.author, me.thumbnail ORDER BY last_update DESC LIMIT ?) me LEFT JOIN reads pindols ON (me.id = pindols.article_id AND pindols.user_id = 9) WHERE (pindols.user_id IS NULL) ORDER BY last_update DESC: '20' 

Конечно, вы можете пропустить пейджинг, но у меня он был в моем коде, поэтому я включил его здесь.

Особая благодарность град от # dbix-class на irc.perl.org и https://blog.afoolishmanifesto.com/posts/dbix-class-parameterized-relationships/.

Спасибо, Canto

1

Я даже не знаю, что Catalyst есть, но я могу взломать запрос SQL:

select articles.id, reads.user_id 
from 
    articles 
    left join 
    (
     select * 
     from reads 
     where user_id = 9 
    ) reads on articles.id = reads.article_id 
order by articles.last_update desc 
limit 5; 
+0

спасибо. Катализатор - это веб-фреймворк на основе MVC perl. Учитывая, что это не является строгим ответом на катализатор, я не буду отмечать как разрешенный. Я посмотрю. Возможно, это обходное решение поможет :) Прошу прощения, но я пока не могу проголосовать, недостаточно репутации :( – canto