如何使用Doctrine本机查询按条件语句的连接计数对结果进行排序?

时间:2018-09-20 11:40:20

标签: mysql symfony doctrine-orm orm symfony-3.4

我想从poll表中选择行,并按已连接vote表中vote.is_current_vote = true的行数或行总数对它们进行排序。

“投票”表会跟踪所有投票,但是在投票中只记录每位用户的最新投票,投票标记为is_current_vote

我正在努力研究如何使用“ Doctrine查询生成器”或“本机查询”来获取Vote表的计数。

这是数据库结构:

create table if not exists user
(
    id int auto_increment
        primary key,
    username varchar(45) not null,
    slug varchar(45) not null,
    created_at datetime not null,
    updated_at datetime null,
    constraint UNIQ_8D93D649989D9B62
        unique (slug),
    constraint UNIQ_8D93D649F85E0677
        unique (username)
)
collate=utf8_unicode_ci
;

create table if not exists poll
(
    id int auto_increment
        primary key,
    user_id int null,
    question varchar(140) not null,
    slug varchar(140) not null,
    is_active tinyint(1) not null,
    created_at datetime not null,
    updated_at datetime null,
    constraint UNIQ_84BCFA45989D9B62
        unique (slug),
    constraint FK_84BCFA45A76ED395
        foreign key (user_id) references user (id)
)
collate=utf8_unicode_ci
;

create index IDX_84BCFA45A76ED395
    on poll (user_id)
;

create table if not exists vote
(
    id int auto_increment
        primary key,
    poll_id int not null,
    user_id int not null,
    created_at datetime not null,
    is_current_vote tinyint(1) not null,
    constraint FK_5A1085643C947C0F
        foreign key (poll_id) references poll (id),
    constraint FK_5A108564A76ED395
        foreign key (user_id) references user (id),
)
collate=utf8_unicode_ci
;

create index IDX_5A1085643C947C0F
    on vote (poll_id)
;

create index IDX_5A108564A76ED395
    on vote (user_id)
;

我在MySQL中运行此查询,这为我提供了我想要的数据:

select poll.id, poll.slug, poll.question, poll.created_at,
       u.id, u.username, u.slug, u.profile_picture,
       sum(case when v.is_current_vote = true then 1 else 0 end) as total_votes
from poll
       left join user u on poll.user_id = u.id
       left join vote v on poll.id = v.poll_id
group by poll.id
order by total_votes desc

数据应按“ v.is_current_vote = true”的票数排序。
示例数据(省略了上面的某些列,因此更易于阅读):

poll.question, u.username, total_votes  
Is Elvis Alive?, someone, 15  
Is the future bright?, someone_else, 10  
Is this all a dream?, another_user, 5  

是否可以在Symfony / Doctrine QueryBuilder语句中执行类似的操作,还是必须使用本机SQL?我也无法解决该怎么做。非常感谢您提供一些指导。

这是我当前的本机SQL尝试,我从poll表中获得行,但表决和用户均为null

/**
 * Class PollRepository
 * @package PollBundle\Repository
 */
class PollRepository extends EntityRepository
{

 /**
     * @return \Doctrine\ORM\NativeQuery
     */
    public function findPopular()
    {
        $rsm = new ResultSetMappingBuilder($this->_em);
        $rsm->addRootEntityFromClassMetadata('PollBundle\Entity\Poll', 'poll');
        $rsm->addJoinedEntityFromClassMetadata('PollBundle\Entity\User', 'u', 'poll', 'user', [
            'id' => 'user_id',
            'slug' => 'user_slug',
            'created_at' => 'user_created_at',
            'updated_at' => 'user_updated_at',
            'is_active' => 'user_is_active',
        ]);
        $rsm->addJoinedEntityFromClassMetadata('PollBundle\Entity\Vote', 'v', 'poll', 'votes', [
            'id' => 'vote_id',
            'user_id' => 'vote_user_id',
            'created_at' => 'vote_created_at',
            'updated_at' => 'vote_updated_at',
        ]);

        $sql = '
            SELECT poll.id, poll.slug, poll.question, poll.created_at,
                   u.id, u.username, u.slug, u.profile_picture,
                   sum(case when v.is_current_vote = true then 1 else 0 end) as total_votes
            from poll
                   left join user u on poll.user_id = u.id
                   left join vote v on poll.id = v.poll_id
            group by poll.id
            order by total_votes desc
        ';

        return $this->_em->createNativeQuery($sql, $rsm)->getResult();
    }
}

1 个答案:

答案 0 :(得分:1)

您是否尝试过与此查询类似的内容? Doctrine几乎可以完成SQL的所有工作。

$query = $this->createQueryBuilder('p')
   ->select('p.question, u.username, count(v.isCurrentVote) AS votes')
   // joins maybe need change depending on your relations
   ->leftJoin('p.user', 'u')
   ->leftJoin('p.votes', 'v')
   ->groupBy('p.id')
   ->orderBy('votes');
return $query->getQuery()->getResult();