Как я могу использовать Doctrine Native Query для упорядочивания результатов по количеству соединений с условным оператором?

Я хочу выбрать строки из таблицы poll и отсортировать их по количеству или сумме строк объединенной таблицы vote, где vote.is_current_vote = true.

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

Я изо всех сил пытаюсь понять, как получить счет в таблице голосования с помощью Doctrine Query Builder или Native Query.

Вот структура базы данных:

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();
    }
}

@Strawberry Спасибо за ссылку, которую я раньше не читал. Вы просите меня предоставить более четкие определения таблиц и примеры ожидаемых строк, или что-то еще я делаю не так?

OrderAndChaos 20.09.2018 14:03

@Sarcoma Вы можете предоставить базовую структуру таблицы (здесь показаны только соответствующие столбцы для рассматриваемой проблемы); некоторые минимальные образцы данных, которые могут воспроизвести ваш случай, и ожидаемый результат. Обратите внимание, что вы можете не предоставить фактическое значение данных, подойдут только некоторые примерные репрезентативные значения!

Madhur Bhaiya 20.09.2018 14:31

Конечно без проблем. У меня есть что-то вроде (я думаю) с использованием Doctrine Native Query, это тоже добавит.

OrderAndChaos 20.09.2018 14:39

@MadhurBhaiya Я добавил SQL для создания таблиц, с которыми я работаю, и примера ожидаемого результата. Я оставил столбцы, такие как slug и created_at, поскольку они конфликтуют между столбцами.

OrderAndChaos 20.09.2018 15:03

@ Strawberry Я добавил некоторые дополнительные сведения и информацию, это помогает?

OrderAndChaos 20.09.2018 15:04

Нет. Честно говоря, я думаю, что принятый ответ на связанный вопрос не требует пояснений.

Strawberry 20.09.2018 15:14

@ Клубничный ха, да ладно. Видимо не в моем случае.

OrderAndChaos 20.09.2018 15:19
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
8
211
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы пробовали что-то похожее на этот запрос? Доктрина может делать почти все, что может делать 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();

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

OrderAndChaos 20.09.2018 17:11

Я думаю, что смогу его использовать, но результаты такие: 0 => 0 => Poll {}, "votes" => "4"], поэтому у него есть дополнительный ассоциативный массив, который мне не нужен. Я хочу как-нибудь сплющить его. Я посмотрю что я могу сделать.

OrderAndChaos 20.09.2018 17:14

Попробуйте удалить «голосов AS» и заменить «голосов» внутри -> orderBy на номер столбца результата.

Vyctorya 20.09.2018 17:17

Было бы полезно иметь счетчик для отображения. Я не уверен, что вы имеете в виду под «заменить 'голосов' внутри-> orderBy номером столбца результатов»

OrderAndChaos 20.09.2018 17:34

Можете ли вы где-нибудь выложить результат и объяснить, что вам нужно изменить?

Vyctorya 20.09.2018 17:48

Я как бы хочу, чтобы голоса были прикреплены как поле к объекту опросов. Но я думаю, мне придется жить с этим как есть. Я получил долгую работу от Native Query и в итоге получил именно то, что QueryBuilder достиг в 7 строках! Спасибо за помощь, это поможет. Я мог бы заглянуть в подготовленные утверждения рядом, чтобы увидеть, предлагают ли они решение.

OrderAndChaos 20.09.2018 18:04

Вы также можете создать функцию внутри своего класса Poll, например getVotes () {$ count = 0; foreach ($ this-> голосует как $ vote) {if ($ vote-> getIsCurrentVote ()) {$ count + = 1; }} return $ count; } Это позволит выполнить фильтрацию с помощью PHP, что может немного замедлить работу вашего приложения, но голоса будут прикреплены к опросу.

Vyctorya 21.09.2018 09:14

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

OrderAndChaos 21.09.2018 10:01

Другие вопросы по теме