Сложная хранимая процедура MySQL - PullRequest
3 голосов
/ 24 марта 2009

У меня есть полусложная хранимая процедура, которую мне нужно создать. Я не совсем администратор, но никто в моей компании не лучше меня. Основная идея в том, что у меня есть группа задач. Пользователь выполняет эти задачи и получает флаг за каждую выполненную задачу. Чтобы считаться «завершенным», пользователь должен завершить всю группу заданных задач. Пинк Линч состоит в том, что некоторые из этих задач могут быть обертками для других групп задач.

Например, у нас есть следующие возможные задачи:

Task 1
Task 2 
Task 3
Task 4 -> (1, 2, 3)
Task 5 -> (1, 2)
Task 6
Task 7 -> (5, 6)

Как только пользователь завершил задачи 1 и 2, он неявно завершил задачу 5. Как только он завершит задачу 3, у него будет неявно выполненная задача 4.

Если другой пользователь завершит задания 1, 2 и 6, он будет неявно завершить задания 1, 2, 5, 6, 7.

В обратном порядке, если для назначения требуется только задание 7, оно, соответственно, потребует задания 6 и 5, для чего потребуются 1 и 2.

У меня есть пять основных таблиц: userCompletedTask, assignmentRequiredTask, componentTask, userTaskAssignment и task. Я опускаю таблицу пользователей и назначений, так как она излишняя.

userCompletedTask:
userID (Foreign Key on user)
taskID (Foreign Key on task)

usertTaskAssignment:
userID (Foreign key on user)
assignmentID (Foreign key on assignment)

assignmentRequiredTask:
assignmentID (Foreign key on assignment)
taskID (Foreign key on task)

task:
taskID (primary key)
compound (boolean flag. If 1, it is compound)

compoundTask:
parentID (foreign key on task)
childID (foreign key on task)

Пользователь получает присвоение userTaskAssignment, которое требует выполнения задачи 4. Я хочу построить хранимую процедуру, которая будет проверять userCompletedTasks против assignmentRequiredTasks, проверяя, есть ли соответствующие составные задачи.

Псевдокод будет выглядеть так:

collection tasksCompleted = user->getTasksCompleted
collection tasksRequired = new collection

foreach task in assignment->getRequiredTasks 
   if(task.isCompound) 
      tasksRequired->addAll(getCompountTasks(task))
   else 
      tasksRequired->add(task)

if tasksCompleted->containsAll(tasksRequired)
   return true
else 
   return false

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

EDIT

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

Ответы [ 3 ]

1 голос
/ 24 марта 2009

Действительно, ваша таблица compoundTask дублирует вашу таблицу task. Если вы просто добавите обнуляемый столбец parent_id в таблицу задач, вы сможете добиться таких же результатов в одной таблице.

Вот и все, это непроверенный и, возможно, даже недействительный MySQL, но он должен помочь вам начать:

SELECT DISTINCT taskID FROM task AS t LEFT JOIN compoundTask AS ct ON ct.taskID = t.taskID
INNER JOIN userCompletedTask AS uct ON uct.taskID = t.taskID
INNER JOIN userCompletedTask AS uctCompound ON uctCompound.taskID = ct.taskID
WHERE uct.userID = @user AND uctCompound.userID = @user

Что бы из этого не было возвращено taskID, они завершаются для указанного @user.

Прошло много времени с тех пор, как я работал с MySQL, так что это может даже не сработать. Кроме того, если бы вы могли объединить таблицы compoundTask и task, 2-й INNER JOIN был бы не нужен.

0 голосов
/ 24 марта 2009

Если у вас когда-либо будет только один уровень задач, то лучшей моделью может быть таблица задач и таблица подзадач. Для несложных задач у них будет просто одна подзадача вместо кратных. Вы можете сделать это в своей собственной модели, просто добавив строки для всех не составных задач, где parentid = childid.

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

SELECT
    COALESCE(CT.child_id, T.task_id)
FROM
    User_Task_Assignments UTA
INNER JOIN Assignment_Required_Tasks ART ON
    ART.assignment_id = UTA.assignment_id
INNER JOIN Tasks T ON
    T.task_id = ART.task_id
LEFT OUTER JOIN Compound_Tasks CT ON
    CT.parent_task_id = T.task_id AND
    T.compound = 1
LEFT OUTER JOIN User_Completed_Tasks UCT ON
    UCT.user_id = @user_id AND
    UCT.task_id = COALESCE(CT.child_id, T.task_id)
WHERE
    UTA.user_id = @user_id AND
    UCT.user_id IS NULL
0 голосов
/ 24 марта 2009

Я новичок в MySQL, но я не новичок в процедурах хранения T-SQL. Вот что я думаю должна быть хранимая процедура. Я думаю, что это смесь T-SQL и MySQL .... поэтому, пожалуйста, устраните проблемы с синтаксисом соответственно

CREATE PROCEDURE proc (@userId BIGINT)
AS
BEGIN

/*
   Consider this table the same as
   collection tasksCompleted = user->getTasksCompleted
*/
CREATE TABLE #TasksCompleted
(
   taskID BIGINT
);

INSERT INTO #TaskCompleted
   (SELECT
    task.taskId
    FROM
    userCompletedTask natural join
    task
    WHERE
    userCompletedTask.userId = @userID AND
    task.completed = 1);


/*
   Same as collection tasksRequired = new collection
*/
CREATE TABLE #RequiredTasks
(
   taskID BIGINT
);

CREATE TABLE #RetrivedRequiredTasks
(
   taskID BIGINT,
   compound BIT
);

INSERT INTO #RetrivedRequiredTasks
   (SELECT
    task.taskId,
    task.compound
    FROM
    usertTaskAssignment NATURAL JOIN
    assignmentRequiredTask NATURAL JOIN
    task
    WHERE
    userCompletedTask.userId = @userID);

INSERT INTO #RequiredTasks
   (SELECT taskID FROM #RetrivedRequiredTasks WHERE compound = 0);

INSERT INTO #RequiredTasks
   (SELECT
    compoundTask.childID
    FROM
    #RetrivedRequiredTasks INNER JOIN
    compoundTask on
    (
        #RetrivedRequiredTasks.compound = true  AND
        #RetrivedRequiredTasks.taskId = compoundTask.parentID
    ));

DECLARE @count INT

SELECT @count = Count(*)
FROM #RequiredTasks
WHERE taskId NOT IN (
    SELECT taskID FROM #TaskCompleted);

IF @count = 0 THEN
   SELECT 1 /* All required tasks completed */
ELSE
   SELECT 0 /* vice-versa */

END

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...