Как рассчитать процент архитектуры вложенных таблиц в mysql

Моя текущая архитектура таблиц следующая:

  1. Карточный стол (Родительский стол: Card)
  2. Каждая карточка имеет один или несколько списков (Второй ребенок lists)
  3. В каждом списке много задач (третий ребенок tasks)
  4. Всякий раз, когда пользователь выполняет задачу, она будет заполнена в отдельной таблице под названием (user_tasks)

Так что если вы хотите представить это как дерево Карточка => много списков карточек => много списков задач.

Карта

ID | Имя

Списки

ID | Card_ID | Имя

Задания

ID | Lists_Id | Card_Id | Заголовок

Пользовательские задачи

Идентификатор | ID_задачи | Идентификатор_пользователя | Содержание

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

Прогресс карты рассчитывается по тому, насколько списки пользователя полностью заполнены.

Примеры:

  1. На карточке 1 3 списка, в каждом по 4 задания.

Пользователь заполнил все задачи (4x3) в этих списках прогресс карты будет 3/3.

  1. На карточке 1 3 списка, в каждом по 4 задания.

Пользователь выполнил все задачи в любых 2 списках (4x2) прогресс карты будет 2/3

  1. На карточке 1 3 списка, в каждом по 4 задания.

Пользователь заполнил только 2 задачи в списке 1, который содержит 4 задачи, прогресс карты будет 0/3

Таким образом, чтобы считать список выполненным, пользователь должен выполнить все свои задачи. Может ли кто-нибудь подсказать мне, как реализовать логику архитектуры вложенных таблиц, чтобы карты продвигались, пожалуйста?

Поэтому я ожидаю, что вывод будет следующим:

{
   card_id: 1,
   total_lists: 10
   total_filled: 3
}

И так далее, по всем картам в базе...

Предоставьте образцы данных и желаемые результаты в виде табличного текста.

GMB 20.12.2020 17:59

Как их обеспечить? схема нужна? @ГМБ

mba3gar 20.12.2020 18:00

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

GMB 20.12.2020 18:01

@GMB хорошо, я сделал несколько правок

mba3gar 20.12.2020 18:06

См. meta.stackoverflow.com/questions/333952/…

Strawberry 20.12.2020 21:32
Освоение архитектуры микросервисов с 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
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
2
5
125
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Вы можете использовать следующий запрос

SELECT target.cardid as 'card_id', target.total as 'total_lists', IFNULL(progress.total,0) as 'total_filled'
FROM   (SELECT l.cardid, Count(l.id) total 
        FROM   lists l 
        GROUP  BY l.cardid) target
LEFT JOIN (SELECT l.cardid, userlist.userid, Count(userlist.listid) total 
                   FROM   lists l 
                          INNER JOIN (SELECT ut.userid, t1.listid, Count(ut.taskid) tcount 
                                      FROM   user_tasks ut 
                                             INNER JOIN tasks t1 ON t1.id = ut.taskid 
                                      GROUP  BY ut.userid, t1.listid) userlist --- STEP#1
                                  ON l.id = userlist.listid 
                          INNER JOIN (SELECT t.listid, Count(*) tcount 
                                      FROM   tasks t 
                                      GROUP  BY t.listid) tasklist --- STEP#2
                                  ON userlist.listid = tasklist.listid  AND userlist.tcount = tasklist.tcount --- STEP#3
                   GROUP  BY l.cardid, userlist.userid) progress  -- STEP#4
ON target.cardid = progress.cardid; 

Описание:

  • Step#1: Определите количество задач для каждого user_id и list_id.
  • Step#2: определить количество задач на list_id для всех списков.
  • Step#3: фильтровать записи в user_task, в которых нет записей для всех задач в списке.
  • Step#4: получить количество списков в user_task, в котором есть записи для всех задач.
  • Наконец, присоединитесь к подзапросам target и progress, чтобы получить окончательный результат.

Демо: https://www.db-fiddle.com/f/5tAzoL49SSd2SJDK5k19a3/3


Примечание: Пара замечаний

  1. В идеале на столе tasks не должно быть cardid, должно присутствовать только listid.
  2. Могут ли 2 разных пользователя работать на одной карте? В этом случае в результат также необходимо включить userid. Обратитесь - https://www.db-fiddle.com/f/5tAzoL49SSd2SJDK5k19a3/4

Это кажется более сложным, чем нужно? Я думаю, что должен быть только один подзапрос

ysth 22.12.2020 07:07

@ysth, я изо всех сил старался упростить это. Даже не в состоянии сделать это с функциями mysql 8. Было бы здорово, если бы вы воспользовались этой ссылкой, db-fiddle.com/f/5tAzoL49SSd2SJDK5k19a3/3, и опубликовали упрощенный ответ, пожалуйста? Требование — это % списков в user_tasks по отношению к общему количеству списков для карты и пользователя. Список в user_tasks необходимо учитывать только в том случае, если в нем есть записи для всех задач в списке.

Prasanna 22.12.2020 07:23
db-fiddle.com/f/mHdQuhLY6QVoHkGyLrNPYE/2
ysth 22.12.2020 10:50

@ysth Потрясающе!!! Не могли бы вы опубликовать этот ответ? Должно помочь mba3gar

Prasanna 22.12.2020 11:24

Большое спасибо, ребята. но я не понял вашего вопроса, что вы имеете в виду, что 2 разных пользователя могут работать на одной и той же карте? он уже включен в user_tasks. Вы рекомендуете лучшую архитектуру для более простого запроса?

mba3gar 22.12.2020 17:49

@ mba3gar, мне было любопытно, что в вашем результате вы показываете total_filled против card_id. Что, если процент 1 пользователя составляет 100, а другого пользователя - 50 для этой карты? Является ли это возможным? Если это так, вы не должны включать user_id в результат?

Prasanna 22.12.2020 18:42

@ mba3gar, также я предлагаю вам сначала попробовать решение ysh. Это намного проще. Если это работает для вас, пожалуйста, примите этот ответ. Поможет людям в будущем.

Prasanna 22.12.2020 18:46

Да вопрос уже принят. Но весь проект делается на основе пользователя. Как будто перед этим запросом есть аутентификация.

mba3gar 22.12.2020 22:48

Это довольно просто. Чтобы найти все списки с задачами и проверить, все ли их задачи заполнены, вы делаете это:

select lists.id,
     count(tasks.id)=count(user_tasks.id) filled  
from lists
join tasks on tasks.lists_id=lists.id
left join user_tasks on user_tasks.task_id=tasks.id
group by lists.id

Чтобы получить отчет о количестве полных и заполненных списков на карточку, вы используете это как подзапрос (добавляя card_id, чтобы иметь возможность искать списки по карточкам):

select card.id,
    count(card_lists.id) as total_lists,
    sum(card_lists.filled) as total_filled
from card
join (
    select lists.id, lists.card_id,
        count(tasks.id)=count(user_tasks.id) filled  
    from lists
    join tasks on tasks.lists_id=lists.id
    left join user_tasks on user_tasks.task_id=tasks.id
    group by lists.id, lists.card_id
) card_lists on card_lists.card_id=card.id
group by card.id

Если задачу могут выполнять несколько пользователей, измените count(user_tasks.id) на count(distinct user_tasks.tasks_id).

Большое спасибо, это было действительно полезно, и я действительно должен вам помочь <3 .

mba3gar 22.12.2020 17:50

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