Моя текущая архитектура таблиц следующая:
Card
)lists
)tasks
)user_tasks
)Так что если вы хотите представить это как дерево Карточка => много списков карточек => много списков задач.
ID | Имя
ID | Card_ID | Имя
ID | Lists_Id | Card_Id | Заголовок
Идентификатор | ID_задачи | Идентификатор_пользователя | Содержание
Теперь мне нужно написать запрос или простую логику, которую я вообще не могу понять, чтобы рассчитать прогресс каждой карты.
Прогресс карты рассчитывается по тому, насколько списки пользователя полностью заполнены.
Примеры:
Пользователь заполнил все задачи (4x3) в этих списках прогресс карты будет 3/3.
Пользователь выполнил все задачи в любых 2 списках (4x2) прогресс карты будет 2/3
Пользователь заполнил только 2 задачи в списке 1, который содержит 4 задачи, прогресс карты будет 0/3
Таким образом, чтобы считать список выполненным, пользователь должен выполнить все свои задачи. Может ли кто-нибудь подсказать мне, как реализовать логику архитектуры вложенных таблиц, чтобы карты продвигались, пожалуйста?
Поэтому я ожидаю, что вывод будет следующим:
{
card_id: 1,
total_lists: 10
total_filled: 3
}
И так далее, по всем картам в базе...
Как их обеспечить? схема нужна? @ГМБ
Всего несколько репрезентативных строк из каждой таблицы вместе с соответствующим результатом - все в виде табличного текста (у SO есть хорошие варианты форматирования таблиц).
@GMB хорошо, я сделал несколько правок
См. meta.stackoverflow.com/questions/333952/…
Вы можете использовать следующий запрос
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
Примечание: Пара замечаний
tasks
не должно быть cardid
, должно присутствовать только listid
.userid
. Обратитесь - https://www.db-fiddle.com/f/5tAzoL49SSd2SJDK5k19a3/4Это кажется более сложным, чем нужно? Я думаю, что должен быть только один подзапрос
@ysth, я изо всех сил старался упростить это. Даже не в состоянии сделать это с функциями mysql 8. Было бы здорово, если бы вы воспользовались этой ссылкой, db-fiddle.com/f/5tAzoL49SSd2SJDK5k19a3/3, и опубликовали упрощенный ответ, пожалуйста? Требование — это % списков в user_tasks по отношению к общему количеству списков для карты и пользователя. Список в user_tasks необходимо учитывать только в том случае, если в нем есть записи для всех задач в списке.
@ysth Потрясающе!!! Не могли бы вы опубликовать этот ответ? Должно помочь mba3gar
Большое спасибо, ребята. но я не понял вашего вопроса, что вы имеете в виду, что 2 разных пользователя могут работать на одной и той же карте? он уже включен в user_tasks. Вы рекомендуете лучшую архитектуру для более простого запроса?
@ mba3gar, мне было любопытно, что в вашем результате вы показываете total_filled против card_id. Что, если процент 1 пользователя составляет 100, а другого пользователя - 50 для этой карты? Является ли это возможным? Если это так, вы не должны включать user_id в результат?
@ mba3gar, также я предлагаю вам сначала попробовать решение ysh. Это намного проще. Если это работает для вас, пожалуйста, примите этот ответ. Поможет людям в будущем.
Да вопрос уже принят. Но весь проект делается на основе пользователя. Как будто перед этим запросом есть аутентификация.
Это довольно просто. Чтобы найти все списки с задачами и проверить, все ли их задачи заполнены, вы делаете это:
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 .
Предоставьте образцы данных и желаемые результаты в виде табличного текста.